diff --git a/.vscode/launch.json b/.vscode/launch.json index 6b21f9497a..05202901da 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ "runtimeExecutable": "${execPath}", "args": ["--extensionDevelopmentPath=${workspaceRoot}"], "sourceMaps": true, - "outFiles": ["${workspaceRoot}/dist/*.js"], + "outFiles": ["${workspaceRoot}/dist/*.{js,mjs}"], "preLaunchTask": "packageDev" }, { @@ -24,7 +24,7 @@ "csharp-test-profile", "${workspaceRoot}/test/untrustedWorkspace/integrationTests/testAssets/empty/.vscode/empty.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test/untrustedWorkspace/integrationTests", + "--extensionTestsPath=${workspaceRoot}/out/test/untrustedWorkspace/integrationTests/index.js", "--log", "ms-dotnettools.csharp:trace" ], @@ -33,7 +33,7 @@ }, "sourceMaps": true, "outFiles": [ - "${workspaceRoot}/dist/*.js", + "${workspaceRoot}/dist/*.{js,mjs}", "${workspaceRoot}/out/test/**/*.js" ], "resolveSourceMapLocations": [ @@ -56,7 +56,7 @@ "csharp-test-profile", "${workspaceRoot}/test/lsptoolshost/integrationTests/testAssets/slnWithCsproj/.vscode/slnWithCsproj.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test/lsptoolshost/integrationTests", + "--extensionTestsPath=${workspaceRoot}/out/test/lsptoolshost/integrationTests/index.js", "--log", "ms-dotnettools.csharp:trace" ], @@ -66,7 +66,7 @@ "RoslynWaiterEnabled": "true" }, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/dist/*.js", "${workspaceRoot}/out/test/**/*.js"], + "outFiles": ["${workspaceRoot}/dist/*.{js,mjs}", "${workspaceRoot}/out/test/**/*.js"], "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"], "preLaunchTask": "packageDev", "internalConsoleOptions": "openOnSessionStart" @@ -84,7 +84,7 @@ "csharp-test-profile", "${workspaceRoot}/test/lsptoolshost/integrationTests/testAssets/slnWithCsproj/.vscode/devkit_slnWithCsproj.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test/lsptoolshost/integrationTests", + "--extensionTestsPath=${workspaceRoot}/out/test/lsptoolshost/integrationTests/index.js", "--log", "ms-dotnettools.csharp:trace" ], @@ -94,7 +94,7 @@ "RoslynWaiterEnabled": "true" }, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/dist/*.js", "${workspaceRoot}/out/test/**/*.js"], + "outFiles": ["${workspaceRoot}/dist/*.{js,mjs}", "${workspaceRoot}/out/test/**/*.js"], "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"], "preLaunchTask": "packageDev", "internalConsoleOptions": "openOnSessionStart" @@ -112,7 +112,7 @@ "csharp-test-profile", "${workspaceRoot}/test/razor/razorIntegrationTests/testAssets/RazorApp/.vscode/RazorApp.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test/razor/razorIntegrationTests", + "--extensionTestsPath=${workspaceRoot}/out/test/razor/razorIntegrationTests/index.js", "--log", "ms-dotnettools.csharp:trace" ], @@ -121,7 +121,7 @@ "TEST_FILE_FILTER": "${file}" }, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/dist/*.js", "${workspaceRoot}/out/test/**/*.js"], + "outFiles": ["${workspaceRoot}/dist/*.{js,mjs}", "${workspaceRoot}/out/test/**/*.js"], "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"], "preLaunchTask": "packageDev", "internalConsoleOptions": "openOnSessionStart" @@ -139,7 +139,7 @@ "csharp-test-profile", "${workspaceRoot}/test/omnisharp/omnisharpIntegrationTests/testAssets/${input:omnisharpAssetName}/.vscode/omnisharp_${input:omnisharpAssetName}.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test/omnisharp/omnisharpIntegrationTests" + "--extensionTestsPath=${workspaceRoot}/out/test/omnisharp/omnisharpIntegrationTests/index.js" ], "env": { "CODE_EXTENSIONS_PATH": "${workspaceRoot}", @@ -147,7 +147,7 @@ "TEST_FILE_FILTER": "${file}" }, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/dist/*.js", "${workspaceRoot}/out/test/**/*.js"], + "outFiles": ["${workspaceRoot}/dist/*.{js,mjs}", "${workspaceRoot}/out/test/**/*.js"], "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"], "preLaunchTask": "packageDev" }, @@ -164,7 +164,7 @@ "csharp-test-profile", "${workspaceRoot}/test/omnisharp/omnisharpIntegrationTests/testAssets/${input:omnisharpAssetName}/.vscode/omnisharp_lsp_${input:omnisharpAssetName}.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", - "--extensionTestsPath=${workspaceRoot}/out/test/omnisharp/omnisharpIntegrationTests" + "--extensionTestsPath=${workspaceRoot}/out/test/omnisharp/omnisharpIntegrationTests/index.js" ], "env": { "CODE_EXTENSIONS_PATH": "${workspaceRoot}", @@ -172,7 +172,7 @@ "TEST_FILE_FILTER": "${file}" }, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/dist/*.js", "${workspaceRoot}/out/test/**/*.js"], + "outFiles": ["${workspaceRoot}/dist/*.{js,mjs}", "${workspaceRoot}/out/test/**/*.js"], "resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"], "preLaunchTask": "packageDev" }, @@ -181,8 +181,8 @@ "request": "launch", "name": "Debug task", "preLaunchTask": "build", - "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js", - "args": ["tasks/${input:taskScript}"], + "runtimeArgs": ["--import", "tsx"], + "program": "${workspaceFolder}/tasks/${input:taskScript}", "cwd": "${workspaceFolder}" }, { @@ -190,8 +190,8 @@ "request": "launch", "name": "Update OmniSharp package dependencies", "preLaunchTask": "build", - "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js", - "args": ["tasks/debugger/updatePackageDependencies.ts"], + "runtimeArgs": ["--import", "tsx"], + "program": "${workspaceFolder}/tasks/debugger/updatePackageDependencies.ts", "env": { "NEW_DEPS_ID": "OmniSharp", "NEW_DEPS_URLS": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-x64.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-x86.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-arm64.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-osx.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-win-x64.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-win-arm64.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-musl-x64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-musl-arm64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-x64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-linux-arm64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-osx-x64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-osx-arm64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-win-x64-net6.0.zip,https://roslynomnisharp.blob.core.windows.net/releases/1.39.14/omnisharp-win-arm64-net6.0.zip", @@ -205,8 +205,8 @@ "request": "launch", "name": "Update razor telemetry package dependencies", "preLaunchTask": "build", - "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js", - "args": ["tasks/debugger/updatePackageDependencies.ts"], + "runtimeArgs": ["--import", "tsx"], + "program": "${workspaceFolder}/tasks/debugger/updatePackageDependencies.ts", "env": { "NEW_DEPS_URLS": "https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/704e369c5905f9ece819ebce77fb78d8/devkittelemetry-linux-arm64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/4049a66147717a53860bbc969bf32faa/devkittelemetry-linux-musl-arm64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/c75e84ff813be5c9833d96dc2066a364/devkittelemetry-linux-musl-x64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/f58cf629939f0df77d142be881f9e233/devkittelemetry-linux-x64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/1c912419ea45c8d95cfa28a8a04640dc/devkittelemetry-osx-arm64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/36545ba0998f1fc380e877e38b2f35f1/devkittelemetry-osx-x64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/0a32698e8ba1ab93489d79f34f8ae8d0/devkittelemetry-platformagnostic-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/4f16ff826fedd33ad80d265c5409588b/devkittelemetry-win-arm64-7.0.0-preview.24178.4.zip,https://download.visualstudio.microsoft.com/download/pr/534f8426-a4f4-4b2d-b3ba-c4e16a38c48c/5a98d8f4e481dbb7ae3cdb3695b75c46/devkittelemetry-win-x64-7.0.0-preview.24178.4.zip", "NEW_DEPS_VERSION": "7.0.0-preview.24178.4", @@ -219,8 +219,8 @@ "request": "launch", "name": "Generate debugger options schema", "preLaunchTask": "build", - "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js", - "args": ["tasks/debugger/generateOptionsSchema.ts"], + "runtimeArgs": ["--import", "tsx"], + "program": "${workspaceFolder}/tasks/debugger/generateOptionsSchema.ts", "cwd": "${workspaceFolder}" }, { @@ -228,8 +228,8 @@ "request": "launch", "name": "Razor Cohost integration tests", "preLaunchTask": "build", - "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js", - "args": ["tasks/tests/testIntegrationRazorCohost.ts"], + "runtimeArgs": ["--import", "tsx"], + "program": "${workspaceFolder}/tasks/tests/testIntegrationRazorCohost.ts", "cwd": "${workspaceFolder}" } ], diff --git a/.vscodeignore b/.vscodeignore index b1a2737ee7..57e8717e36 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -49,7 +49,7 @@ package-lock.json tsconfig.json version.json wallaby.js -esbuild.js +esbuild.mjs !src/razor/language-configuration.json !src/razor/syntaxes/* diff --git a/__mocks__/vscode.ts b/__mocks__/vscode.ts index 5b3bd3dfaf..04689a515d 100644 --- a/__mocks__/vscode.ts +++ b/__mocks__/vscode.ts @@ -12,4 +12,4 @@ import { getFakeVsCode } from '../test/fakes.ts'; // We can consider switching to an actual jest mock (instead of this manual fake) once we entirely // remove the old test framework (mocha/chai). const vscode: vscodeAdapter.vscode = getFakeVsCode(); -module.exports = vscode; +export const { commands, languages, window, workspace, extensions, Uri, version, env, l10n } = vscode; diff --git a/baseJestConfig.mjs b/baseJestConfig.mjs new file mode 100644 index 0000000000..79be385071 --- /dev/null +++ b/baseJestConfig.mjs @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { fileURLToPath } from 'node:url'; +import { createDefaultEsmPreset, createDefaultPreset } from 'ts-jest'; + +const tsconfigPath = fileURLToPath(new URL('./tsconfig.json', import.meta.url)); +const jestTsconfigPath = fileURLToPath(new URL('./tsconfig.jest.json', import.meta.url)); +const commonProjectConfig = { + testEnvironment: 'node', + transformIgnorePatterns: ['/dist/.+\\.js'], +}; + +/** + * Defines a base project config that we can re-use across the project specific jest configs. + * We do this because jest generally does not inherit project configuration settings. + */ +/** @type {import('jest').Config} */ +export const baseProjectConfig = { + ...createDefaultEsmPreset({ tsconfig: tsconfigPath }), + ...commonProjectConfig, + moduleNameMapper: { + // TypeScript rewrites source .ts specifiers to .js before Jest resolves the source module. + '^(\\.{1,2}/.*)\\.js$': '$1', + }, +}; + +// VS Code's packaged extension host strips the Node flag required by Jest's VM-module ESM runtime. +export const baseIntegrationProjectConfig = { + ...createDefaultPreset({ tsconfig: jestTsconfigPath }), + ...commonProjectConfig, + moduleNameMapper: { + // TypeScript rewrites source .ts specifiers to .js before Jest resolves the source module. + '^(\\.{1,2}/.*)\\.js$': '$1', + }, +}; diff --git a/baseJestConfig.ts b/baseJestConfig.ts deleted file mode 100644 index e7894b749f..0000000000 --- a/baseJestConfig.ts +++ /dev/null @@ -1,18 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; - -/** - * Defines a base project config that we can re-use across the project specific jest configs. - * We do this because jest generally does not inherit project configuration settings. - */ -export const baseProjectConfig: Config = { - preset: 'ts-jest', - testEnvironment: 'node', - moduleNameMapper: { - '^(\\.{1,2}/.*)\\.js$': '$1', - }, - transformIgnorePatterns: ['/dist/.+\\.js'], -}; diff --git a/esbuild.js b/esbuild.js deleted file mode 100644 index 54ff1c1803..0000000000 --- a/esbuild.js +++ /dev/null @@ -1,76 +0,0 @@ -const esbuild = require("esbuild"); -const fs = require('fs/promises'); - -const production = process.argv.includes('--production'); -const watch = process.argv.includes('--watch'); - -/** - * @type {import('esbuild').Plugin} - */ -const esbuildProblemMatcherPlugin = { - name: 'esbuild-problem-matcher', - - setup(build) { - build.onStart(() => { - console.log('[watch] build started'); - }); - build.onEnd((result) => { - result.errors.forEach(({ text, location }) => { - console.error(`✘ [ERROR] ${text}`); - console.error(` ${location.file}:${location.line}:${location.column}:`); - }); - console.log('[watch] build finished'); - }); - }, -}; - -/** - * Some VSCode libraries include UMD versions that are not esbuild compatible, and also have broken ESM packages. - * This plugin replaces the UMD imports with the ESM imports. - * See https://github.com/microsoft/vscode/issues/192144 - */ -const umdEsmLoaderPlugin = { - name: 'umdEsmLoaderPlugin', - - setup(build) { - build.onLoad({ filter: /(vscode-html-languageservice|jsonc-parser).*lib[\/\\]umd/ }, async (moduleArgs) => { - // replace the umd path with the esm path from the package. - const newPath = moduleArgs.path.replace(/(.*)lib([\/\\])umd(.*)/, '$1lib$2esm$3'); - const contents = await fs.readFile(newPath, 'utf8'); - return { contents: contents }; - }); - }, -}; - -async function main() { - const ctx = await esbuild.context({ - entryPoints: [ - 'src/main.ts' - ], - bundle: true, - format: 'cjs', - minify: production, - sourcemap: !production, - sourcesContent: false, - platform: 'node', - outfile: 'dist/extension.js', - external: ['vscode', 'applicationinsights-native-metrics', '@opentelemetry/tracing'], - logLevel: 'info', - plugins: [ - umdEsmLoaderPlugin, - /* add to the end of plugins array */ - esbuildProblemMatcherPlugin, - ], - }); - if (watch) { - await ctx.watch(); - } else { - await ctx.rebuild(); - await ctx.dispose(); - } -} - -main().catch(e => { - console.error(e); - process.exit(1); -}); \ No newline at end of file diff --git a/esbuild.mjs b/esbuild.mjs new file mode 100644 index 0000000000..9188d7a734 --- /dev/null +++ b/esbuild.mjs @@ -0,0 +1,133 @@ +import esbuild from 'esbuild'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { auditBundle } from './tasks/compilation/bundleAudit.mjs'; + +const production = process.argv.includes('--production'); +const watch = process.argv.includes('--watch'); + +/** + * @type {import('esbuild').Plugin} + */ +const esbuildProblemMatcherPlugin = { + name: 'esbuild-problem-matcher', + + setup(build) { + build.onStart(() => { + console.log('[watch] build started'); + }); + build.onEnd((result) => { + result.errors.forEach(({ text, location }) => { + console.error(`✘ [ERROR] ${text}`); + console.error(` ${location.file}:${location.line}:${location.column}:`); + }); + console.log('[watch] build finished'); + }); + }, +}; + +/** + * Some VSCode libraries include UMD versions that are not esbuild compatible, and also have broken ESM packages. + * This plugin replaces the UMD imports with the ESM imports. + * See https://github.com/microsoft/vscode/issues/192144 + */ +const umdEsmLoaderPlugin = { + name: 'umdEsmLoaderPlugin', + + setup(build) { + build.onLoad({ filter: /(vscode-html-languageservice|jsonc-parser).*lib[\/\\]umd/ }, async (moduleArgs) => { + // replace the umd path with the esm path from the package. + const newPath = moduleArgs.path.replace(/(.*)lib([\/\\])umd(.*)/, '$1lib$2esm$3'); + const contents = await fs.readFile(newPath, 'utf8'); + return { contents: contents }; + }); + }, +}; + +/** + * The telemetry package advertises an ESM module but has no exports map, so esbuild's Node + * resolution otherwise selects its CommonJS main entry. + */ +const telemetryEsmLoaderPlugin = { + name: 'telemetryEsmLoaderPlugin', + + setup(build) { + build.onResolve({ filter: /^@vscode\/extension-telemetry$/ }, async () => { + const packageDirectory = path.resolve('node_modules/@vscode/extension-telemetry'); + const packageMetadata = JSON.parse( + await fs.readFile(path.join(packageDirectory, 'package.json'), 'utf8') + ); + if (typeof packageMetadata.module !== 'string') { + throw new Error('@vscode/extension-telemetry no longer declares an ESM module entry.'); + } + + return { path: path.resolve(packageDirectory, packageMetadata.module) }; + }); + }, +}; + +const bundleAuditPlugin = { + name: 'bundleAuditPlugin', + + setup(build) { + build.onEnd(async (result) => { + if (result.errors.length > 0) { + return; + } + + try { + await auditBundle(result.metafile, production); + } catch (error) { + return { + errors: [{ text: error instanceof Error ? error.message : String(error) }], + }; + } + }); + }, +}; + +async function main() { + const ctx = await esbuild.context({ + entryPoints: ['src/main.ts'], + bundle: true, + format: 'esm', + // Bundled CommonJS dependencies still use require and CommonJS path globals at runtime. + // The exact require owners are enforced by bundleAuditPlugin so this bridge cannot grow unnoticed. + banner: { + js: [ + `import { createRequire } from 'node:module';`, + `import { dirname as __pathDirname } from 'node:path';`, + `import { fileURLToPath as __fileURLToPath } from 'node:url';`, + `const require = createRequire(import.meta.url);`, + `const __filename = __fileURLToPath(import.meta.url);`, + `const __dirname = __pathDirname(__filename);`, + ].join('\n'), + }, + metafile: true, + minify: production, + sourcemap: !production, + sourcesContent: false, + platform: 'node', + outfile: 'dist/extension.mjs', + external: ['vscode', 'applicationinsights-native-metrics', '@opentelemetry/tracing'], + logLevel: 'info', + plugins: [ + umdEsmLoaderPlugin, + telemetryEsmLoaderPlugin, + /* add to the end of plugins array */ + esbuildProblemMatcherPlugin, + bundleAuditPlugin, + ], + }); + if (watch) { + await ctx.watch(); + } else { + await ctx.rebuild(); + await ctx.dispose(); + } +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/eslint.config.mjs b/eslint.config.mjs index d5c3dfd9f1..f8d8073d55 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -23,7 +23,15 @@ const compatibleHeaderPlugin = fixupPluginRules({ export default defineConfig([ { - ignores: ['out/**', 'dist/**', 'wallaby.js', 'eslint.config.mjs', 'esbuild.js', '**/*.d.ts'], + ignores: [ + 'out/**', + 'dist/**', + '.vscode-test/**', + 'wallaby.js', + 'eslint.config.mjs', + 'esbuild.mjs', + '**/*.d.ts', + ], }, { files: ['**/*.ts'], diff --git a/jest.config.ts b/jest.config.mjs similarity index 83% rename from jest.config.ts rename to jest.config.mjs index 54ca228dea..a27f4be457 100644 --- a/jest.config.ts +++ b/jest.config.mjs @@ -2,19 +2,18 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; - -const config: Config = { +/** @type {import('jest').Config} */ +const config = { projects: [ - '/test/lsptoolshost/artifactTests/jest.config.ts', - '/test/lsptoolshost/integrationTests/jest.config.ts', - '/test/lsptoolshost/unitTests/jest.config.ts', - '/test/omnisharp/omnisharpIntegrationTests/jest.config.ts', - '/test/omnisharp/omnisharpUnitTests/jest.config.ts', - '/test/razor/razorIntegrationTests/jest.config.ts', - '/test/razor/razorTests/jest.config.ts', - '/test/untrustedWorkspace/integrationTests/jest.config.ts', - '/test/tasks/jest.config.ts', + '/test/lsptoolshost/artifactTests/jest.config.mjs', + '/test/lsptoolshost/integrationTests/jest.config.mjs', + '/test/lsptoolshost/unitTests/jest.config.mjs', + '/test/omnisharp/omnisharpIntegrationTests/jest.config.mjs', + '/test/omnisharp/omnisharpUnitTests/jest.config.mjs', + '/test/razor/razorIntegrationTests/jest.config.mjs', + '/test/razor/razorTests/jest.config.mjs', + '/test/untrustedWorkspace/integrationTests/jest.config.mjs', + '/test/tasks/jest.config.mjs', ], // Reporters are a global jest configuration property and cannot be set in the project jest config. // This configuration will create a 'junit.xml' file in the output directory, no matter which test project is running. diff --git a/msbuild/signing/signJs/signJs.proj b/msbuild/signing/signJs/signJs.proj index c2cd518069..502447df9a 100644 --- a/msbuild/signing/signJs/signJs.proj +++ b/msbuild/signing/signJs/signJs.proj @@ -21,5 +21,8 @@ MicrosoftSHA2 + + MicrosoftSHA2 + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2ded849b77..481b41c06b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@github/copilot-language-server": "1.290.0", "@microsoft/servicehub-framework": "4.2.99-beta", - "@vscode/extension-telemetry": "^0.9.0", + "@vscode/extension-telemetry": "^1.5.2", "@vscode/js-debug-browsers": "^1.1.0", "archiver": "5.3.0", "execa": "4.0.0", @@ -58,8 +58,7 @@ "nerdbank-gitversioning": "^3.6.79-alpha", "prettier": "3.9.6", "tmp": "0.2.7", - "ts-jest": "^29.1.1", - "ts-node": "10.9.2", + "ts-jest": "^29.4.1", "tsx": "^4.20.6", "typescript": "5.7.3", "typescript-eslint": "^8.65.0", @@ -835,30 +834,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha1-AGKcNaaI4FqIsc2mhPudXnPwAKE=", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha1-ZTT9WTOlO6fL86F2FeJzoNEnP/k=", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", @@ -2168,104 +2143,110 @@ } }, "node_modules/@microsoft/1ds-core-js": { - "version": "4.0.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-core-js/-/1ds-core-js-4.0.4.tgz", - "integrity": "sha512-QOCE0fTDOMNptB791chnVlfnRvb7faDQTaUIO3DfPBkvjF3PUAJJCsqJKWitw7nwVn8L82TFx+K22UifIr0zkg==", + "version": "4.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-core-js/-/1ds-core-js-4.4.3.tgz", + "integrity": "sha1-4uVAxnLi3V8G9H9iYTirVg5A1z4=", + "license": "MIT", "dependencies": { - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "node_modules/@microsoft/1ds-post-js": { - "version": "4.0.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-post-js/-/1ds-post-js-4.0.4.tgz", - "integrity": "sha512-jlPNL16iRXzmXfriGXv0INzrAl3AeDx+eCORjq8ZjRhIvohB6Q88m5E28nL6Drf5hJWE2ehoW4q8Vh612VoEHw==", + "version": "4.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-post-js/-/1ds-post-js-4.4.3.tgz", + "integrity": "sha1-/3LD505NjEkQ3+q0DamOU0H9SHM=", + "license": "MIT", "dependencies": { - "@microsoft/1ds-core-js": "4.0.4", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "node_modules/@microsoft/applicationinsights-channel-js": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.0.5.tgz", - "integrity": "sha512-KfTYY0uZmrQgrz8ErBh1q08eiYfzjUIVzJZHETgEkqv3l2RTndQgpmywDbVNf9wVTB7Mp89ZrFeCciVJFf5geg==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.4.3.tgz", + "integrity": "sha1-lv6aE/XGMzH2jAP+Yfyo0nP87X8=", + "license": "MIT", "dependencies": { - "@microsoft/applicationinsights-common": "3.0.5", - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" }, "peerDependencies": { - "tslib": "*" + "tslib": ">= 1.0.0" } }, "node_modules/@microsoft/applicationinsights-common": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-common/-/applicationinsights-common-3.0.5.tgz", - "integrity": "sha512-ahph1fMqyLcZ1twzDKMzpHRgR9zEIyqNhMQxDgQ45ieVD641bZiYVwSlbntSXhGCtr5G5HE02zlEzwSxbx95ng==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-common/-/applicationinsights-common-3.4.3.tgz", + "integrity": "sha1-gg7ByONwX7NQuJdFMc6lO/+KhWs=", + "license": "MIT", "dependencies": { - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" }, "peerDependencies": { - "tslib": "*" + "tslib": ">= 1.0.0" } }, "node_modules/@microsoft/applicationinsights-core-js": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.0.5.tgz", - "integrity": "sha512-/x+tkxsVALNWSvwGMyaLwFPdD3p156Pef9WHftXrzrKkJ+685nhrwm9MqHIyEHHpSW09ElOdpJ3rfFVqpKRQyQ==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.4.3.tgz", + "integrity": "sha1-2tJKf5V4gfubq5ZDh2r6Wws54Lo=", + "license": "MIT", "dependencies": { "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" }, "peerDependencies": { - "tslib": "*" + "tslib": ">= 1.0.0" } }, "node_modules/@microsoft/applicationinsights-shims": { "version": "3.0.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-shims/-/applicationinsights-shims-3.0.1.tgz", - "integrity": "sha512-DKwboF47H1nb33rSUfjqI6ryX29v+2QWcTrRvcQDA32AZr5Ilkr7whOOSsD1aBzwqX0RJEIP1Z81jfE3NBm/Lg==", + "integrity": "sha1-OGW3Os6EBbnEYYzFxXHy/jh28G8=", + "license": "MIT", "dependencies": { "@nevware21/ts-utils": ">= 0.9.4 < 2.x" } }, "node_modules/@microsoft/applicationinsights-web-basic": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-web-basic/-/applicationinsights-web-basic-3.0.5.tgz", - "integrity": "sha512-ps4wjmF9X80hakYxywlzBdSlDjfToZrz/cHKA/9yarrW3mbZGqjjksNoaFxtyU5BK4lhOvrgu+2+QcDHeEEnOA==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-web-basic/-/applicationinsights-web-basic-3.4.3.tgz", + "integrity": "sha1-Jq1prhzQVMjUMHCQAeJVKTb6dU0=", + "license": "MIT", "dependencies": { - "@microsoft/applicationinsights-channel-js": "3.0.5", - "@microsoft/applicationinsights-common": "3.0.5", - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-channel-js": "3.4.3", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" }, "peerDependencies": { - "tslib": "*" + "tslib": ">= 1.0.0" } }, "node_modules/@microsoft/dynamicproto-js": { - "version": "2.0.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.2.tgz", - "integrity": "sha512-MB8trWaFREpmb037k/d0bB7T2BP7Ai24w1e1tbz3ASLB0/lwphsq3Nq8S9I5AsI5vs4zAQT+SB5nC5/dLYTiOg==", + "version": "2.0.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.5.tgz", + "integrity": "sha1-9NCLCwbFcNaerXzSq69BQCUITGc=", + "license": "MIT", "dependencies": { - "@nevware21/ts-utils": ">= 0.9.4 < 2.x" + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "node_modules/@microsoft/servicehub-framework": { @@ -2295,17 +2276,18 @@ } }, "node_modules/@nevware21/ts-async": { - "version": "0.3.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-async/-/ts-async-0.3.0.tgz", - "integrity": "sha512-ZUcgUH12LN/F6nzN0cYd0F/rJaMLmXr0EHVTyYfaYmK55bdwE4338uue4UiVoRqHVqNW4KDUrJc49iGogHKeWA==", + "version": "0.5.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-async/-/ts-async-0.5.5.tgz", + "integrity": "sha1-UJZI48PDqpq2E8AMce7k/pvYo8M=", + "license": "MIT", "dependencies": { - "@nevware21/ts-utils": ">= 0.10.0 < 2.x" + "@nevware21/ts-utils": ">= 0.12.2 < 2.x" } }, "node_modules/@nevware21/ts-utils": { - "version": "0.14.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-utils/-/ts-utils-0.14.0.tgz", - "integrity": "sha1-nmB0zijwsbq3v9rNGndgsrpzaI0=", + "version": "0.16.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-utils/-/ts-utils-0.16.0.tgz", + "integrity": "sha1-5KOcjrEi54ESMVx5oAkWI4t/PEw=", "funding": [ { "type": "github", @@ -2969,34 +2951,6 @@ "@textlint/ast-node-types": "15.4.0" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha1-vlfOrB5GkrQb6d5r6MMqEGY226Q=", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha1-7j3vHyfZ7WbaxuRqKVz/sBUuBY0=", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha1-5DhjFihPALmENb9A9y91oJ2r9sE=", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha1-C5LcwMwcgfbzBqOB8o4xsaVlNuk=", - "dev": true, - "license": "MIT" - }, "node_modules/@types/archiver": { "version": "5.1.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/archiver/-/archiver-5.1.0.tgz", @@ -3528,13 +3482,16 @@ "license": "0BSD" }, "node_modules/@vscode/extension-telemetry": { - "version": "0.9.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@vscode/extension-telemetry/-/extension-telemetry-0.9.0.tgz", - "integrity": "sha512-37RxGHXrs3GoXPgCUKQhghEu0gxs8j27RLjQwwtSf4WhPdJKz8UrqMYzpsXlliQ05zURYmtdGZst9C6+hfWXaQ==", + "version": "1.5.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@vscode/extension-telemetry/-/extension-telemetry-1.5.2.tgz", + "integrity": "sha1-KsL23kVWWOJgGA/l6r9zvNbaUUY=", + "license": "MIT", "dependencies": { - "@microsoft/1ds-core-js": "^4.0.3", - "@microsoft/1ds-post-js": "^4.0.3", - "@microsoft/applicationinsights-web-basic": "^3.0.4" + "@microsoft/1ds-core-js": "^4.4.1", + "@microsoft/1ds-post-js": "^4.4.1", + "@microsoft/applicationinsights-common": "^3.4.1", + "@microsoft/applicationinsights-core-js": "^3.4.1", + "@microsoft/applicationinsights-web-basic": "^3.4.1" }, "engines": { "vscode": "^1.75.0" @@ -4093,19 +4050,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/acorn-walk/-/acorn-walk-8.3.5.tgz", - "integrity": "sha1-imuMqPxbNGha8V2rtEEYZjwpZJY=", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/agent-base/-/agent-base-7.1.4.tgz", @@ -4253,7 +4197,9 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/arg/-/arg-4.1.3.tgz", "integrity": "sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk=", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/argparse": { "version": "1.0.10", @@ -5152,7 +5098,9 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/create-require/-/create-require-1.1.1.tgz", "integrity": "sha1-wdfo8eX2z8n/ZfnNNS03NIdWwzM=", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -5401,6 +5349,8 @@ "integrity": "sha1-em2/2jJfJfB1F+m1GPiXwIMy4H0=", "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { "node": ">=0.3.1" } @@ -6672,6 +6622,28 @@ "integrity": "sha1-QYPk6L8Iu24Fu7L30uDI9xLKQOM=", "license": "ISC" }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha1-bxOQgqtY3E5aDlHv59ta6JDVag8=", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has/-/has-1.0.3.tgz", @@ -8734,8 +8706,7 @@ "version": "1.2.6", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true, - "optional": true + "dev": true }, "node_modules/minipass": { "version": "7.1.2", @@ -8841,6 +8812,13 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", + "dev": true, + "license": "MIT" + }, "node_modules/nerdbank-gitversioning": { "version": "3.6.79-alpha", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/nerdbank-gitversioning/-/nerdbank-gitversioning-3.6.79-alpha.tgz", @@ -10579,6 +10557,19 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha1-BP58f54e0tZiIzwoyys1ufY/bk8=", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/spdx-correct": { "version": "3.1.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -11133,37 +11124,44 @@ } }, "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.4.12", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha1-w0zZHwLTZOkobSwBaEMxX9Dv/3Y=", "dev": true, + "license": "MIT", "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.5", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" }, "peerDependenciesMeta": { "@babel/core": { "optional": true }, + "@jest/transform": { + "optional": true + }, "@jest/types": { "optional": true }, @@ -11172,51 +11170,52 @@ }, "esbuild": { "optional": true + }, + "jest-util": { + "optional": true } } }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/semver/-/semver-7.8.5.tgz", + "integrity": "sha1-ObZGA33VDBT7RR5+TKxY7YuGP2k=", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha1-cPAhyeGFvM3Kgg4m3EE4BcEBxx8=", + "version": "9.1.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha1-UamkUKPpWUAb2l8ASnLVS5NtN20=", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", + "source-map-support": "^0.5.17", "yn": "3.1.1" }, "bin": { "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" }, + "engines": { + "node": ">=10.0.0" + }, "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } } }, "node_modules/tslib": { @@ -11371,6 +11370,20 @@ "dev": true, "license": "MIT" }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha1-gjFem7xvKyWIiFis0f/4RBA1t38=", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/uid-safe/-/uid-safe-2.1.5.tgz", @@ -11507,13 +11520,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha1-Yzbo1xllyz01obu3hoRFp8BSZL8=", - "dev": true, - "license": "MIT" - }, "node_modules/v8-to-istanbul": { "version": "9.1.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -11727,6 +11733,13 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11893,6 +11906,8 @@ "integrity": "sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -12524,27 +12539,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha1-AGKcNaaI4FqIsc2mhPudXnPwAKE=", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha1-ZTT9WTOlO6fL86F2FeJzoNEnP/k=", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, "@esbuild/aix-ppc64": { "version": "0.28.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", @@ -13352,92 +13346,90 @@ } }, "@microsoft/1ds-core-js": { - "version": "4.0.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-core-js/-/1ds-core-js-4.0.4.tgz", - "integrity": "sha512-QOCE0fTDOMNptB791chnVlfnRvb7faDQTaUIO3DfPBkvjF3PUAJJCsqJKWitw7nwVn8L82TFx+K22UifIr0zkg==", + "version": "4.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-core-js/-/1ds-core-js-4.4.3.tgz", + "integrity": "sha1-4uVAxnLi3V8G9H9iYTirVg5A1z4=", "requires": { - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/1ds-post-js": { - "version": "4.0.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-post-js/-/1ds-post-js-4.0.4.tgz", - "integrity": "sha512-jlPNL16iRXzmXfriGXv0INzrAl3AeDx+eCORjq8ZjRhIvohB6Q88m5E28nL6Drf5hJWE2ehoW4q8Vh612VoEHw==", + "version": "4.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/1ds-post-js/-/1ds-post-js-4.4.3.tgz", + "integrity": "sha1-/3LD505NjEkQ3+q0DamOU0H9SHM=", "requires": { - "@microsoft/1ds-core-js": "4.0.4", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/applicationinsights-channel-js": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.0.5.tgz", - "integrity": "sha512-KfTYY0uZmrQgrz8ErBh1q08eiYfzjUIVzJZHETgEkqv3l2RTndQgpmywDbVNf9wVTB7Mp89ZrFeCciVJFf5geg==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.4.3.tgz", + "integrity": "sha1-lv6aE/XGMzH2jAP+Yfyo0nP87X8=", "requires": { - "@microsoft/applicationinsights-common": "3.0.5", - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/applicationinsights-common": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-common/-/applicationinsights-common-3.0.5.tgz", - "integrity": "sha512-ahph1fMqyLcZ1twzDKMzpHRgR9zEIyqNhMQxDgQ45ieVD641bZiYVwSlbntSXhGCtr5G5HE02zlEzwSxbx95ng==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-common/-/applicationinsights-common-3.4.3.tgz", + "integrity": "sha1-gg7ByONwX7NQuJdFMc6lO/+KhWs=", "requires": { - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/applicationinsights-core-js": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.0.5.tgz", - "integrity": "sha512-/x+tkxsVALNWSvwGMyaLwFPdD3p156Pef9WHftXrzrKkJ+685nhrwm9MqHIyEHHpSW09ElOdpJ3rfFVqpKRQyQ==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.4.3.tgz", + "integrity": "sha1-2tJKf5V4gfubq5ZDh2r6Wws54Lo=", "requires": { "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/applicationinsights-shims": { "version": "3.0.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-shims/-/applicationinsights-shims-3.0.1.tgz", - "integrity": "sha512-DKwboF47H1nb33rSUfjqI6ryX29v+2QWcTrRvcQDA32AZr5Ilkr7whOOSsD1aBzwqX0RJEIP1Z81jfE3NBm/Lg==", + "integrity": "sha1-OGW3Os6EBbnEYYzFxXHy/jh28G8=", "requires": { "@nevware21/ts-utils": ">= 0.9.4 < 2.x" } }, "@microsoft/applicationinsights-web-basic": { - "version": "3.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-web-basic/-/applicationinsights-web-basic-3.0.5.tgz", - "integrity": "sha512-ps4wjmF9X80hakYxywlzBdSlDjfToZrz/cHKA/9yarrW3mbZGqjjksNoaFxtyU5BK4lhOvrgu+2+QcDHeEEnOA==", + "version": "3.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/applicationinsights-web-basic/-/applicationinsights-web-basic-3.4.3.tgz", + "integrity": "sha1-Jq1prhzQVMjUMHCQAeJVKTb6dU0=", "requires": { - "@microsoft/applicationinsights-channel-js": "3.0.5", - "@microsoft/applicationinsights-common": "3.0.5", - "@microsoft/applicationinsights-core-js": "3.0.5", + "@microsoft/applicationinsights-channel-js": "3.4.3", + "@microsoft/applicationinsights-core-js": "3.4.3", "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.2", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.10.1 < 2.x" + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.5 < 0.6.0", + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/dynamicproto-js": { - "version": "2.0.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.2.tgz", - "integrity": "sha512-MB8trWaFREpmb037k/d0bB7T2BP7Ai24w1e1tbz3ASLB0/lwphsq3Nq8S9I5AsI5vs4zAQT+SB5nC5/dLYTiOg==", + "version": "2.0.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.5.tgz", + "integrity": "sha1-9NCLCwbFcNaerXzSq69BQCUITGc=", "requires": { - "@nevware21/ts-utils": ">= 0.9.4 < 2.x" + "@nevware21/ts-utils": ">= 0.14.0 < 2.x" } }, "@microsoft/servicehub-framework": { @@ -13465,17 +13457,17 @@ } }, "@nevware21/ts-async": { - "version": "0.3.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-async/-/ts-async-0.3.0.tgz", - "integrity": "sha512-ZUcgUH12LN/F6nzN0cYd0F/rJaMLmXr0EHVTyYfaYmK55bdwE4338uue4UiVoRqHVqNW4KDUrJc49iGogHKeWA==", + "version": "0.5.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-async/-/ts-async-0.5.5.tgz", + "integrity": "sha1-UJZI48PDqpq2E8AMce7k/pvYo8M=", "requires": { - "@nevware21/ts-utils": ">= 0.10.0 < 2.x" + "@nevware21/ts-utils": ">= 0.12.2 < 2.x" } }, "@nevware21/ts-utils": { - "version": "0.14.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-utils/-/ts-utils-0.14.0.tgz", - "integrity": "sha1-nmB0zijwsbq3v9rNGndgsrpzaI0=" + "version": "0.16.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@nevware21/ts-utils/-/ts-utils-0.16.0.tgz", + "integrity": "sha1-5KOcjrEi54ESMVx5oAkWI4t/PEw=" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -13989,30 +13981,6 @@ "@textlint/ast-node-types": "15.4.0" } }, - "@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha1-vlfOrB5GkrQb6d5r6MMqEGY226Q=", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha1-7j3vHyfZ7WbaxuRqKVz/sBUuBY0=", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha1-5DhjFihPALmENb9A9y91oJ2r9sE=", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha1-C5LcwMwcgfbzBqOB8o4xsaVlNuk=", - "dev": true - }, "@types/archiver": { "version": "5.1.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/archiver/-/archiver-5.1.0.tgz", @@ -14405,13 +14373,15 @@ } }, "@vscode/extension-telemetry": { - "version": "0.9.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@vscode/extension-telemetry/-/extension-telemetry-0.9.0.tgz", - "integrity": "sha512-37RxGHXrs3GoXPgCUKQhghEu0gxs8j27RLjQwwtSf4WhPdJKz8UrqMYzpsXlliQ05zURYmtdGZst9C6+hfWXaQ==", + "version": "1.5.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@vscode/extension-telemetry/-/extension-telemetry-1.5.2.tgz", + "integrity": "sha1-KsL23kVWWOJgGA/l6r9zvNbaUUY=", "requires": { - "@microsoft/1ds-core-js": "^4.0.3", - "@microsoft/1ds-post-js": "^4.0.3", - "@microsoft/applicationinsights-web-basic": "^3.0.4" + "@microsoft/1ds-core-js": "^4.4.1", + "@microsoft/1ds-post-js": "^4.4.1", + "@microsoft/applicationinsights-common": "^3.4.1", + "@microsoft/applicationinsights-core-js": "^3.4.1", + "@microsoft/applicationinsights-web-basic": "^3.4.1" } }, "@vscode/js-debug-browsers": { @@ -14794,15 +14764,6 @@ "dev": true, "requires": {} }, - "acorn-walk": { - "version": "8.3.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/acorn-walk/-/acorn-walk-8.3.5.tgz", - "integrity": "sha1-imuMqPxbNGha8V2rtEEYZjwpZJY=", - "dev": true, - "requires": { - "acorn": "^8.11.0" - } - }, "agent-base": { "version": "7.1.4", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/agent-base/-/agent-base-7.1.4.tgz", @@ -14909,7 +14870,9 @@ "version": "4.1.3", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/arg/-/arg-4.1.3.tgz", "integrity": "sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "argparse": { "version": "1.0.10", @@ -15562,7 +15525,9 @@ "version": "1.1.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/create-require/-/create-require-1.1.1.tgz", "integrity": "sha1-wdfo8eX2z8n/ZfnNNS03NIdWwzM=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "cross-spawn": { "version": "7.0.6", @@ -15719,7 +15684,9 @@ "version": "4.0.4", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/diff/-/diff-4.0.4.tgz", "integrity": "sha1-em2/2jJfJfB1F+m1GPiXwIMy4H0=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "diff-sequences": { "version": "29.6.3", @@ -16573,6 +16540,19 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha1-QYPk6L8Iu24Fu7L30uDI9xLKQOM=" }, + "handlebars": { + "version": "4.7.9", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha1-bxOQgqtY3E5aDlHv59ta6JDVag8=", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, "has": { "version": "1.0.3", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has/-/has-1.0.3.tgz", @@ -18072,8 +18052,7 @@ "version": "1.2.6", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "7.1.2", @@ -18155,6 +18134,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", + "dev": true + }, "nerdbank-gitversioning": { "version": "3.6.79-alpha", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/nerdbank-gitversioning/-/nerdbank-gitversioning-3.6.79-alpha.tgz", @@ -19338,6 +19323,18 @@ "integrity": "sha1-HOVlD93YerwJnto33P8CTCZnrkY=", "dev": true }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha1-BP58f54e0tZiIzwoyys1ufY/bk8=", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -19730,39 +19727,43 @@ "requires": {} }, "ts-jest": { - "version": "29.1.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.4.12", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-jest/-/ts-jest-29.4.12.tgz", + "integrity": "sha1-w0zZHwLTZOkobSwBaEMxX9Dv/3Y=", "dev": true, "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.8.5", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "semver": { + "version": "7.8.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/semver/-/semver-7.8.5.tgz", + "integrity": "sha1-ObZGA33VDBT7RR5+TKxY7YuGP2k=", + "dev": true + } } }, "ts-node": { - "version": "10.9.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha1-cPAhyeGFvM3Kgg4m3EE4BcEBxx8=", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", + "version": "9.1.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha1-UamkUKPpWUAb2l8ASnLVS5NtN20=", + "dev": true, + "optional": true, + "peer": true, + "requires": { "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", + "source-map-support": "^0.5.17", "yn": "3.1.1" } }, @@ -19863,6 +19864,13 @@ "integrity": "sha1-+NP30OxMPeo1p+PI76TLi0XJ5+4=", "dev": true }, + "uglify-js": { + "version": "3.19.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha1-gjFem7xvKyWIiFis0f/4RBA1t38=", + "dev": true, + "optional": true + }, "uid-safe": { "version": "2.1.5", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/uid-safe/-/uid-safe-2.1.5.tgz", @@ -19948,12 +19956,6 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/uuid/-/uuid-9.0.1.tgz", "integrity": "sha1-4YjUyIU8xyIiA5LEJM1jfzIpPzA=" }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha1-Yzbo1xllyz01obu3hoRFp8BSZL8=", - "dev": true - }, "v8-to-istanbul": { "version": "9.1.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -20113,6 +20115,12 @@ "integrity": "sha1-0sRcbdT7zmIaZvE2y+Mor9BBCzQ=", "dev": true }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -20226,7 +20234,9 @@ "version": "3.1.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/yn/-/yn-3.1.1.tgz", "integrity": "sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "yocto-queue": { "version": "0.1.0", diff --git a/package.json b/package.json index 275bb27b48..8fd4f7a22b 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "csharp", "publisher": "ms-dotnettools", "version": "42.42.42-placeholder", + "type": "module", "description": "Base language support for C#", "displayName": "C#", "author": "Microsoft Corporation", @@ -47,7 +48,7 @@ "xamlTools": "18.10.12014.341", "testDiscovery": "9.9.223-ge3811b" }, - "main": "./dist/extension", + "main": "./dist/extension.mjs", "l10n": "./l10n", "brokeredServices": [ { @@ -78,11 +79,11 @@ "l10nDevGenerateXlf": "npx @vscode/l10n-dev generate-xlf ./package.nls.json ./l10n/bundle.l10n.json --outFile ./loc/vscode-csharp.xlf", "l10nDevImportXlf": "npx @vscode/l10n-dev import-xlf ./loc/vscode-csharp.*.xlf --outDir ./l10n && move l10n\\package.nls.*.json .", "lint": "npx eslint ./", - "omnisharptest": "npm run packageDev && npx ts-node tasks/tests/omnisharptest.ts", - "omnisharptest:integration": "npm run packageDev && npx tsx tasks/tests/omnisharptestIntegration.ts", - "omnisharptest:unit": "npm run compileDev && npx ts-node tasks/tests/omnisharptestUnit.ts", - "package": "npm run compile && npm run signJs && node esbuild.js --production", - "packageDev": "npm run compileDev && node esbuild.js", + "omnisharptest": "npm run packageDev && node --experimental-vm-modules --import tsx tasks/tests/omnisharptest.ts", + "omnisharptest:integration": "npm run packageDev && node --experimental-vm-modules --import tsx tasks/tests/omnisharptestIntegration.ts", + "omnisharptest:unit": "npm run compileDev && node --experimental-vm-modules --import tsx tasks/tests/omnisharptestUnit.ts", + "package": "npm run compile && node esbuild.mjs --production && npm run signJs", + "packageDev": "npm run compileDev && node esbuild.mjs", "prepare": "npm run installDependencies", "profiling": "npm run package && npx tsx tasks/profiling/profiling.ts", "publishLocalizationContent": "npx tsx tasks/localization/publishLocalizationContent.ts", @@ -90,13 +91,13 @@ "signJs": "npx tsx tasks/signing/signJs.ts", "signVsix": "npx tsx tasks/signing/signVsix.ts", "test": "npm run test:unit && npm run test:artifacts", - "test:artifacts": "npm run compileDev && npx ts-node tasks/tests/testArtifacts.ts", + "test:artifacts": "npm run compileDev && node --experimental-vm-modules --import tsx tasks/tests/testArtifacts.ts", "test:integration": "npm run test:integration:csharp && npm run test:integration:devkit && npm run test:integration:razor:cohost && npm run test:integration:untrusted", - "test:integration:csharp": "npm run packageDev && npx tsx tasks/tests/testIntegrationCsharp.ts", - "test:integration:devkit": "npm run packageDev && npx tsx tasks/tests/testIntegrationDevkit.ts", - "test:integration:razor:cohost": "npm run packageDev && npx tsx tasks/tests/testIntegrationRazorCohost.ts", - "test:integration:untrusted": "npm run packageDev && npx tsx tasks/tests/testIntegrationUntrusted.ts", - "test:unit": "npm run compileDev && npx ts-node tasks/tests/testUnit.ts", + "test:integration:csharp": "npm run packageDev && node --experimental-vm-modules --import tsx tasks/tests/testIntegrationCsharp.ts", + "test:integration:devkit": "npm run packageDev && node --experimental-vm-modules --import tsx tasks/tests/testIntegrationDevkit.ts", + "test:integration:razor:cohost": "npm run packageDev && node --experimental-vm-modules --import tsx tasks/tests/testIntegrationRazorCohost.ts", + "test:integration:untrusted": "npm run packageDev && node --experimental-vm-modules --import tsx tasks/tests/testIntegrationUntrusted.ts", + "test:unit": "npm run compileDev && node --experimental-vm-modules --import tsx tasks/tests/testUnit.ts", "updateChangelog": "npx tsx tasks/snap/updateChangelog.ts", "updatePackageDependencies": "npx tsx tasks/debugger/updatePackageDependencies.ts", "updateRoslynVersion": "npx tsx tasks/packaging/updateRoslynVersion.ts", @@ -111,7 +112,7 @@ "dependencies": { "@github/copilot-language-server": "1.290.0", "@microsoft/servicehub-framework": "4.2.99-beta", - "@vscode/extension-telemetry": "^0.9.0", + "@vscode/extension-telemetry": "^1.5.2", "@vscode/js-debug-browsers": "^1.1.0", "archiver": "5.3.0", "execa": "4.0.0", @@ -158,8 +159,7 @@ "nerdbank-gitversioning": "^3.6.79-alpha", "prettier": "3.9.6", "tmp": "0.2.7", - "ts-jest": "^29.1.1", - "ts-node": "10.9.2", + "ts-jest": "^29.4.1", "tsx": "^4.20.6", "typescript": "5.7.3", "typescript-eslint": "^8.65.0", diff --git a/src/activateOmniSharp.ts b/src/activateOmniSharp.ts index f5137bf60d..bf4ac5a6bb 100644 --- a/src/activateOmniSharp.ts +++ b/src/activateOmniSharp.ts @@ -8,7 +8,7 @@ import { OmnisharpExtensionExports } from './csharpExtensionExports.ts'; import { PlatformInformation } from './shared/platform.ts'; import { Observable } from 'rxjs'; import { NetworkSettingsProvider } from './networkSettings.ts'; -import TelemetryReporter from '@vscode/extension-telemetry'; +import { ITelemetryReporter } from './shared/telemetryReporter.ts'; import { activateOmniSharpLanguageServer } from './omnisharp/omnisharpLanguageServer.ts'; import { EventStream } from './eventStream.ts'; import { razorOptions } from './shared/options.ts'; @@ -21,7 +21,7 @@ export function activateOmniSharp( networkSettingsProvider: NetworkSettingsProvider, eventStream: EventStream, csharpChannel: vscode.OutputChannel, - reporter: TelemetryReporter, + reporter: ITelemetryReporter, getCoreClrDebugPromise: (languageServerStarted: Promise) => Promise ): OmnisharpExtensionExports { // activate language services diff --git a/src/activateRoslyn.ts b/src/activateRoslyn.ts index 1faf7b7599..7fca7674ce 100644 --- a/src/activateRoslyn.ts +++ b/src/activateRoslyn.ts @@ -8,7 +8,7 @@ import { CSharpExtensionExports } from './csharpExtensionExports.ts'; import { PlatformInformation } from './shared/platform.ts'; import { Observable } from 'rxjs'; import { EventStream } from './eventStream.ts'; -import TelemetryReporter from '@vscode/extension-telemetry'; +import { ITelemetryReporterWithLevel } from './shared/telemetryReporter.ts'; import { RoslynLanguageServer } from './lsptoolshost/server/roslynLanguageServer.ts'; import { CSharpDevKitExports } from './csharpDevKitExports.ts'; import { RoslynLanguageServerEvents, ServerState } from './lsptoolshost/server/languageServerEvents.ts'; @@ -32,7 +32,7 @@ export function activateRoslyn( optionStream: Observable, eventStream: EventStream, csharpChannel: vscode.LogOutputChannel, - reporter: TelemetryReporter, + reporter: ITelemetryReporterWithLevel, csharpDevkitExtension: vscode.Extension | undefined, getCoreClrDebugPromise: (languageServerStarted: Promise) => Promise ): CSharpExtensionExports { diff --git a/src/lsptoolshost/activate.ts b/src/lsptoolshost/activate.ts index 33008da5d2..072a38ed04 100644 --- a/src/lsptoolshost/activate.ts +++ b/src/lsptoolshost/activate.ts @@ -6,10 +6,11 @@ import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; +import { fileURLToPath } from 'url'; import { registerCommands } from './commands.ts'; import { registerDebugger } from './debugger/debugger.ts'; import { PlatformInformation } from '../shared/platform.ts'; -import TelemetryReporter from '@vscode/extension-telemetry'; +import { ITelemetryReporterWithLevel } from '../shared/telemetryReporter.ts'; import { getCSharpDevKit } from '../utils/getCSharpDevKit.ts'; import { DotnetRuntimeExtensionResolver } from './dotnetRuntime/dotnetRuntimeExtensionResolver.ts'; import { registerUnitTestingCommands } from './testing/unitTesting.ts'; @@ -45,7 +46,7 @@ export async function activateRoslynLanguageServer( platformInfo: PlatformInformation, optionObservable: Observable, outputChannel: ObservableLogOutputChannel, - reporter: TelemetryReporter, + reporter: ITelemetryReporterWithLevel, languageServerEvents: RoslynLanguageServerEvents ): Promise { // Create a channel for outputting general logs from the language server. @@ -158,7 +159,7 @@ export function getServerPath(platformInfo: PlatformInformation) { } function getInstalledServerPath(platformInfo: PlatformInformation): string { - const clientRoot = __dirname; + const clientRoot = path.dirname(fileURLToPath(import.meta.url)); const serverFilePath = path.join(clientRoot, '..', '.roslyn', 'Microsoft.CodeAnalysis.LanguageServer'); let extension = ''; diff --git a/src/lsptoolshost/commands.ts b/src/lsptoolshost/commands.ts index 564ab44b75..ff7752b85d 100644 --- a/src/lsptoolshost/commands.ts +++ b/src/lsptoolshost/commands.ts @@ -17,7 +17,7 @@ import { changeProjectContextFileExplorer, openAndChangeProjectContext, } from './projectContext/projectContextCommands.ts'; -import TelemetryReporter from '@vscode/extension-telemetry'; +import { ITelemetryReporter } from '../shared/telemetryReporter.ts'; import { TelemetryEventNames } from '../shared/telemetryEventNames.ts'; import { registerCollectLogsCommand } from './logging/collectLogs.ts'; import { ObservableLogOutputChannel } from './logging/observableLogOutputChannel.ts'; @@ -28,7 +28,7 @@ export function registerCommands( hostExecutableResolver: IHostExecutableResolver, outputChannel: ObservableLogOutputChannel, csharpTraceChannel: ObservableLogOutputChannel, - reporter: TelemetryReporter + reporter: ITelemetryReporter ) { registerExtensionCommands( context, @@ -51,7 +51,7 @@ function registerExtensionCommands( hostExecutableResolver: IHostExecutableResolver, outputChannel: ObservableLogOutputChannel, csharpTraceChannel: ObservableLogOutputChannel, - reporter: TelemetryReporter + reporter: ITelemetryReporter ) { context.subscriptions.push( vscode.commands.registerCommand( diff --git a/src/lsptoolshost/diagnostics/fixAllCodeAction.ts b/src/lsptoolshost/diagnostics/fixAllCodeAction.ts index a901b8fbcc..6975fdfbfb 100644 --- a/src/lsptoolshost/diagnostics/fixAllCodeAction.ts +++ b/src/lsptoolshost/diagnostics/fixAllCodeAction.ts @@ -7,8 +7,6 @@ import * as vscode from 'vscode'; import * as RoslynProtocol from '../server/roslynProtocol.ts'; import { LSPAny } from 'vscode-languageclient'; import { RoslynLanguageServer } from '../server/roslynLanguageServer.ts'; -import { URIConverter, createConverter } from 'vscode-languageclient/protocolConverter'; -import { UriConverter } from '../utils/uriConverter.ts'; export function registerCodeActionFixAllCommands( context: vscode.ExtensionContext, @@ -56,9 +54,7 @@ export async function getFixAllResponse( ); if (response.edit) { - const uriConverter: URIConverter = (value: string): vscode.Uri => UriConverter.deserialize(value); - const protocolConverter = createConverter(uriConverter, true, true, true); - const fixAllEdit = await protocolConverter.asWorkspaceEdit(response.edit); + const fixAllEdit = await languageServer.protocol2CodeConverter.asWorkspaceEdit(response.edit); if (!(await vscode.workspace.applyEdit(fixAllEdit))) { const componentName = '[roslyn.client.fixAllCodeAction]'; const errorMessage = 'Failed to make a fix all edit for completion.'; diff --git a/src/lsptoolshost/diagnostics/nestedCodeAction.ts b/src/lsptoolshost/diagnostics/nestedCodeAction.ts index d094a2d9d7..a083cf7121 100644 --- a/src/lsptoolshost/diagnostics/nestedCodeAction.ts +++ b/src/lsptoolshost/diagnostics/nestedCodeAction.ts @@ -6,8 +6,6 @@ import * as vscode from 'vscode'; import { CodeAction, CodeActionResolveRequest, LSPAny } from 'vscode-languageclient'; import { RoslynLanguageServer } from '../server/roslynLanguageServer.ts'; -import { URIConverter, createConverter } from 'vscode-languageclient/protocolConverter'; -import { UriConverter } from '../utils/uriConverter.ts'; import { getFixAllResponse } from './fixAllCodeAction.ts'; export function registerNestedCodeActionCommands( @@ -72,10 +70,7 @@ async function registerNestedResolveCodeAction( throw new Error('Tried to retrieve a code action edit, but an error occurred.'); } - const uriConverter: URIConverter = (value: string): vscode.Uri => - UriConverter.deserialize(value); - const protocolConverter = createConverter(uriConverter, true, true, true); - const fixAllEdit = await protocolConverter.asWorkspaceEdit(response.edit); + const fixAllEdit = await languageServer.protocol2CodeConverter.asWorkspaceEdit(response.edit); if (!(await vscode.workspace.applyEdit(fixAllEdit))) { const componentName = '[roslyn.client.nestedCodeAction]'; const errorMessage = 'Failed to make am edit for completion.'; diff --git a/src/lsptoolshost/extensions/builtInComponents.ts b/src/lsptoolshost/extensions/builtInComponents.ts index ff57c429b0..74801869f1 100644 --- a/src/lsptoolshost/extensions/builtInComponents.ts +++ b/src/lsptoolshost/extensions/builtInComponents.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; +import { fileURLToPath } from 'url'; import { LanguageServerOptions } from '../../shared/options.ts'; interface ComponentInfo { @@ -80,5 +81,5 @@ function getComponentFolderPath(component: ComponentInfo, options: LanguageServe } } - return path.join(__dirname, '..', component.defaultFolderName); + return path.join(path.dirname(fileURLToPath(import.meta.url)), '..', component.defaultFolderName); } diff --git a/src/lsptoolshost/server/roslynLanguageServer.ts b/src/lsptoolshost/server/roslynLanguageServer.ts index 251fa7a6a0..fddf29ce7b 100644 --- a/src/lsptoolshost/server/roslynLanguageServer.ts +++ b/src/lsptoolshost/server/roslynLanguageServer.ts @@ -12,6 +12,7 @@ import { NotificationHandler0, NotificationType, PartialResultParams, + Protocol2CodeConverter, ProtocolRequestType, RequestHandler, RequestParam, @@ -27,7 +28,7 @@ import { readConfigurations } from '../options/configurationMiddleware.ts'; import * as RoslynProtocol from './roslynProtocol.ts'; import { CSharpDevKitExports } from '../../csharpDevKitExports.ts'; import { SolutionSnapshotId } from '../solutionSnapshot/ISolutionSnapshotProvider.ts'; -import TelemetryReporter from '@vscode/extension-telemetry'; +import { ITelemetryReporterWithLevel } from '../../shared/telemetryReporter.ts'; import { csharpDevkitExtensionId, getCSharpDevKit } from '../../utils/getCSharpDevKit.ts'; import { randomUUID } from 'crypto'; @@ -91,7 +92,7 @@ export class RoslynLanguageServer { private _languageClient: RoslynLanguageClient, private _platformInfo: PlatformInformation, private _context: vscode.ExtensionContext, - private _telemetryReporter: TelemetryReporter, + private _telemetryReporter: ITelemetryReporterWithLevel, private _languageServerEvents: RoslynLanguageServerEvents, private _channel: vscode.LogOutputChannel, private _traceChannel: vscode.LogOutputChannel @@ -125,6 +126,10 @@ export class RoslynLanguageServer { return this._state; } + public get protocol2CodeConverter(): Protocol2CodeConverter { + return this._languageClient.protocol2CodeConverter; + } + public static get processId(): number | undefined { return RoslynLanguageServer._processId; } @@ -265,7 +270,7 @@ export class RoslynLanguageServer { platformInfo: PlatformInformation, hostExecutableResolver: IHostExecutableResolver, context: vscode.ExtensionContext, - telemetryReporter: TelemetryReporter, + telemetryReporter: ITelemetryReporterWithLevel, additionalExtensionPaths: string[], languageServerEvents: RoslynLanguageServerEvents, channel: vscode.LogOutputChannel, @@ -641,7 +646,7 @@ export class RoslynLanguageServer { platformInfo: PlatformInformation, hostExecutableResolver: IHostExecutableResolver, context: vscode.ExtensionContext, - telemetryReporter: TelemetryReporter, + telemetryReporter: ITelemetryReporterWithLevel, additionalExtensionPaths: string[], channel: vscode.LogOutputChannel, csharpDevKitExtensionExports?: CSharpDevKitExports diff --git a/src/main.ts b/src/main.ts index cd12278cec..00b660b67a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,7 +12,7 @@ import { CsharpChannelObserver } from './shared/observers/csharpChannelObserver. import { CsharpLoggerObserver } from './shared/observers/csharpLoggerObserver.ts'; import { EventStream } from './eventStream.ts'; import { PlatformInformation } from './shared/platform.ts'; -import TelemetryReporter from '@vscode/extension-telemetry'; +import { TelemetryReporter } from '@vscode/extension-telemetry'; import { vscodeNetworkSettingsProvider } from './networkSettings.ts'; import createOptionStream from './shared/observables/createOptionStream.ts'; import { AbsolutePathPackage } from './packageManager/absolutePathPackage.ts'; diff --git a/src/omnisharp/engines/lspEngine.ts b/src/omnisharp/engines/lspEngine.ts index 0295034fcf..ad06c865d7 100644 --- a/src/omnisharp/engines/lspEngine.ts +++ b/src/omnisharp/engines/lspEngine.ts @@ -19,19 +19,25 @@ import { Events, OmniSharpServer } from '../server.ts'; import { IEngine } from './IEngine.ts'; import { PlatformInformation } from '../../shared/platform.ts'; import { IHostExecutableResolver } from '../../shared/constants/IHostExecutableResolver.ts'; -import { Command, RequestType, Trace } from 'vscode-languageclient'; -import { DynamicFeature, LanguageClientOptions, StaticFeature } from 'vscode-languageclient'; +import { + CallHierarchyPrepareRequest, + Command, + DeclarationRequest, + DidChangeWorkspaceFoldersNotification, + DocumentColorRequest, + DocumentDiagnosticRequest, + DocumentLinkRequest, + DynamicFeature, + InlineValueRequest, + LanguageClientOptions, + NotebookDocumentSyncRegistrationType, + RequestType, + SelectionRangeRequest, + StaticFeature, + Trace, + TypeHierarchyPrepareRequest, +} from 'vscode-languageclient'; import { LanguageClient, ServerOptions } from 'vscode-languageclient/node'; -import { SelectionRangeFeature } from 'vscode-languageclient/selectionRange'; -import { ColorProviderFeature } from 'vscode-languageclient/colorProvider'; -import { WorkspaceFoldersFeature } from 'vscode-languageclient/workspaceFolder'; -import { DeclarationFeature } from 'vscode-languageclient/declaration'; -import { DocumentLinkFeature } from 'vscode-languageclient/documentLink'; -import { InlineValueFeature } from 'vscode-languageclient/inlineValue'; -import { DiagnosticFeature } from 'vscode-languageclient/diagnostic'; -import { NotebookDocumentSyncFeature } from 'vscode-languageclient/notebook'; -import { TypeHierarchyFeature } from 'vscode-languageclient/typeHierarchy'; -import { CallHierarchyFeature } from 'vscode-languageclient/callHierarchy'; import { Advisor } from '../features/diagnosticsProvider.ts'; import dotnetTest from '../features/dotnetTest.ts'; @@ -246,41 +252,44 @@ export class LspEngine implements IEngine { // The goal here is to disable all the features and light them up over time. const features: (StaticFeature | DynamicFeature)[] = (client as any)._features; - function disableFeature(ctor: { new (...args: any[]): StaticFeature | DynamicFeature }): void { - const index = features.findIndex((z) => z instanceof ctor); + function disableFeature(featureId: string): void { + const index = features.findIndex((feature) => { + const state = feature.getState(); + return state.kind !== 'static' && state.id === featureId; + }); if (index > -1) { features.splice(index, 1); } } - disableFeature(CallHierarchyFeature); // Not implemented in O# + disableFeature(CallHierarchyPrepareRequest.method); // Not implemented in O# //disableFeature(CodeActionFeature); //disableFeature(CodeLensFeature); // Only supports Reference codelens at this time. Does not support Run/Debug Test codelens. - disableFeature(ColorProviderFeature); // Not implemented in O# + disableFeature(DocumentColorRequest.method); // Not implemented in O# //disableFeature(CompletionItemFeature); - disableFeature(DeclarationFeature); // Not implemented in O# + disableFeature(DeclarationRequest.method); // Not implemented in O# //disableFeature(DefinitionFeature); // Needs metadata document/source generated document support - disableFeature(DiagnosticFeature); + disableFeature(DocumentDiagnosticRequest.method); //disableFeature(DocumentFormattingFeature); //disableFeature(DocumentRangeFormattingFeature); //disableFeature(DocumentOnTypeFormattingFeature); // This feature does not seem to be triggering //disableFeature(DocumentHighlightFeature); - disableFeature(DocumentLinkFeature); // Not implemented in O# + disableFeature(DocumentLinkRequest.method); // Not implemented in O# //disableFeature(DocumentSymbolFeature); //disableFeature(FoldingRangeFeature); //disableFeature(HoverFeature); // This feature does not always seem to be working. Wonder if requests are coming in too early. //disableFeature(ImplementationFeature); // Needs metadata document/source generated document support //disableFeature(InlayHintsFeature); // The csharp-language-server-protocol library needs to update with 3.17 changes - disableFeature(InlineValueFeature); // Not implemented in O# - disableFeature(NotebookDocumentSyncFeature); // Not implemented in O# + disableFeature(InlineValueRequest.method); // Not implemented in O# + disableFeature(NotebookDocumentSyncRegistrationType.method); // Not implemented in O# //disableFeature(ReferencesFeature); // Needs metadata document/source generated document support //disableFeature(RenameFeature); - disableFeature(SelectionRangeFeature); // Not implemented in O# + disableFeature(SelectionRangeRequest.method); // Not implemented in O# //disableFeature(SemanticTokensFeature); // This feature does not always seem to be working. Wonder if requests are coming in too early. //disableFeature(SignatureHelpFeature); //disableFeature(TypeDefinitionFeature); // Needs metadata document/source generated document support - disableFeature(TypeHierarchyFeature); // Not implemented in O# - disableFeature(WorkspaceFoldersFeature); // Not implemented in O# + disableFeature(TypeHierarchyPrepareRequest.method); // Not implemented in O# + disableFeature(DidChangeWorkspaceFoldersNotification.method); // Not implemented in O# //disableFeature(WorkspaceSymbolFeature); const interopFeature = this.createInteropFeature(client); diff --git a/src/omnisharp/features/definitionMetadataDocumentProvider.ts b/src/omnisharp/features/definitionMetadataDocumentProvider.ts index 05a62745d3..a795df57ec 100644 --- a/src/omnisharp/features/definitionMetadataDocumentProvider.ts +++ b/src/omnisharp/features/definitionMetadataDocumentProvider.ts @@ -1,60 +1,60 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TextDocument, TextDocumentContentProvider, Uri, workspace } from 'vscode'; -import { MetadataResponse } from '../protocol.ts'; -import { IDisposable } from '../../disposable.ts'; - -export default class DefinitionMetadataDocumentProvider implements TextDocumentContentProvider, IDisposable { - readonly scheme = 'omnisharp-metadata'; - private _registration?: IDisposable; - private _documents: Map; - private _documentClosedSubscription: IDisposable; - - constructor() { - this._documents = new Map(); - this._documentClosedSubscription = workspace.onDidCloseTextDocument(this.onTextDocumentClosed, this); - } - - private onTextDocumentClosed(document: TextDocument): void { - this._documents.delete(document.uri.toString()); - } - - public dispose(): void { - this._registration?.dispose(); - this._documentClosedSubscription.dispose(); - this._documents.clear(); - } - - public addMetadataResponse(metadataResponse: MetadataResponse): Uri { - const uri = this.createUri(metadataResponse.SourceName); - this._documents.set(uri.toString(), metadataResponse); - - return uri; - } - - public getExistingMetadataResponseUri(sourceName: string): Uri { - return this.createUri(sourceName); - } - - public hasMetadataDocument(sourceName: string): boolean { - const uri = this.createUri(sourceName); - return this._documents.has(uri.toString()); - } - - public register(): void { - this._registration = workspace.registerTextDocumentContentProvider(this.scheme, this); - } - - public provideTextDocumentContent(uri: Uri): string | undefined { - return this._documents.get(uri.toString())?.Source; - } - - private createUri(sourceName: string): Uri { - return Uri.parse( - this.scheme + '://' + sourceName.replace(/\\/g, '/').replace(/(.*)\/(.*)/g, '$1/[metadata] $2') - ); - } -} +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TextDocument, TextDocumentContentProvider, Uri, workspace } from 'vscode'; +import { MetadataResponse } from '../protocol.ts'; +import { IDisposable } from '../../disposable.ts'; + +export default class DefinitionMetadataDocumentProvider implements TextDocumentContentProvider, IDisposable { + readonly scheme = 'omnisharp-metadata'; + private _registration?: IDisposable; + private _documents: Map; + private _documentClosedSubscription: IDisposable; + + constructor() { + this._documents = new Map(); + this._documentClosedSubscription = workspace.onDidCloseTextDocument(this.onTextDocumentClosed, this); + } + + private onTextDocumentClosed(document: TextDocument): void { + this._documents.delete(document.uri.toString()); + } + + public dispose(): void { + this._registration?.dispose(); + this._documentClosedSubscription.dispose(); + this._documents.clear(); + } + + public addMetadataResponse(metadataResponse: MetadataResponse): Uri { + const uri = this.createUri(metadataResponse.SourceName); + this._documents.set(uri.toString(), metadataResponse); + + return uri; + } + + public getExistingMetadataResponseUri(sourceName: string): Uri { + return this.createUri(sourceName); + } + + public hasMetadataDocument(sourceName: string): boolean { + const uri = this.createUri(sourceName); + return this._documents.has(uri.toString()); + } + + public register(): void { + this._registration = workspace.registerTextDocumentContentProvider(this.scheme, this); + } + + public provideTextDocumentContent(uri: Uri): string | undefined { + return this._documents.get(uri.toString())?.Source; + } + + private createUri(sourceName: string): Uri { + return Uri.parse( + this.scheme + '://' + sourceName.replace(/\\/g, '/').replace(/(.*)\/(.*)/g, '$1/[metadata] $2') + ); + } +} diff --git a/src/omnisharp/features/workspaceSymbolProvider.ts b/src/omnisharp/features/workspaceSymbolProvider.ts index 18f2e4e0a3..36facb3c68 100644 --- a/src/omnisharp/features/workspaceSymbolProvider.ts +++ b/src/omnisharp/features/workspaceSymbolProvider.ts @@ -1,96 +1,96 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import AbstractSupport from './abstractProvider.ts'; -import { OmniSharpServer } from '../server.ts'; -import * as protocol from '../protocol.ts'; -import * as serverUtils from '../utils.ts'; -import { toRange } from '../typeConversion.ts'; -import { CancellationToken, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Location } from 'vscode'; -import { LanguageMiddlewareFeature } from '../languageMiddlewareFeature.ts'; -import SourceGeneratedDocumentProvider from './sourceGeneratedDocumentProvider.ts'; -import { omnisharpOptions } from '../../shared/options.ts'; - -export default class OmniSharpWorkspaceSymbolProvider extends AbstractSupport implements WorkspaceSymbolProvider { - constructor( - server: OmniSharpServer, - languageMiddlewareFeature: LanguageMiddlewareFeature, - private sourceGeneratedDocumentProvider: SourceGeneratedDocumentProvider - ) { - super(server, languageMiddlewareFeature); - } - - public async provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { - const minFindSymbolsFilterLength = omnisharpOptions.minFindSymbolsFilterLength; - const maxFindSymbolsItems = omnisharpOptions.maxFindSymbolsItems; - const minFilterLength = minFindSymbolsFilterLength > 0 ? minFindSymbolsFilterLength : undefined; - const maxItemsToReturn = maxFindSymbolsItems > 0 ? maxFindSymbolsItems : undefined; - - if (minFilterLength !== undefined && search.length < minFilterLength) { - return []; - } - - try { - const res = await serverUtils.findSymbols( - this._server, - { Filter: search, MaxItemsToReturn: maxItemsToReturn }, - token - ); - if (Array.isArray(res?.QuickFixes)) { - return res.QuickFixes.map((symbol) => this._asSymbolInformation(symbol)); - } - } catch { - /* empty */ - } - - return []; - } - - private _asSymbolInformation(symbolInfo: protocol.SymbolLocation): SymbolInformation { - let uri: Uri; - if (symbolInfo.GeneratedFileInfo) { - uri = this.sourceGeneratedDocumentProvider.addSourceGeneratedFileWithoutInitialContent( - symbolInfo.GeneratedFileInfo, - symbolInfo.FileName - ); - } else { - uri = Uri.file(symbolInfo.FileName); - } - - const location = new Location(uri, toRange(symbolInfo)); - - return new SymbolInformation( - symbolInfo.Text, - OmniSharpWorkspaceSymbolProvider._toKind(symbolInfo), - symbolInfo.ContainingSymbolName ?? '', - location - ); - } - - private static _toKind(symbolInfo: protocol.SymbolLocation): SymbolKind { - switch (symbolInfo.Kind) { - case 'Method': - return SymbolKind.Method; - case 'Field': - return SymbolKind.Field; - case 'Property': - return SymbolKind.Property; - case 'Interface': - return SymbolKind.Interface; - case 'Enum': - return SymbolKind.Enum; - case 'Struct': - return SymbolKind.Struct; - case 'Event': - return SymbolKind.Event; - case 'EnumMember': - return SymbolKind.EnumMember; - case 'Class': - return SymbolKind.Class; - default: - return SymbolKind.Class; - } - } -} +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import AbstractSupport from './abstractProvider.ts'; +import { OmniSharpServer } from '../server.ts'; +import * as protocol from '../protocol.ts'; +import * as serverUtils from '../utils.ts'; +import { toRange } from '../typeConversion.ts'; +import { CancellationToken, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Location } from 'vscode'; +import { LanguageMiddlewareFeature } from '../languageMiddlewareFeature.ts'; +import SourceGeneratedDocumentProvider from './sourceGeneratedDocumentProvider.ts'; +import { omnisharpOptions } from '../../shared/options.ts'; + +export default class OmniSharpWorkspaceSymbolProvider extends AbstractSupport implements WorkspaceSymbolProvider { + constructor( + server: OmniSharpServer, + languageMiddlewareFeature: LanguageMiddlewareFeature, + private sourceGeneratedDocumentProvider: SourceGeneratedDocumentProvider + ) { + super(server, languageMiddlewareFeature); + } + + public async provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { + const minFindSymbolsFilterLength = omnisharpOptions.minFindSymbolsFilterLength; + const maxFindSymbolsItems = omnisharpOptions.maxFindSymbolsItems; + const minFilterLength = minFindSymbolsFilterLength > 0 ? minFindSymbolsFilterLength : undefined; + const maxItemsToReturn = maxFindSymbolsItems > 0 ? maxFindSymbolsItems : undefined; + + if (minFilterLength !== undefined && search.length < minFilterLength) { + return []; + } + + try { + const res = await serverUtils.findSymbols( + this._server, + { Filter: search, MaxItemsToReturn: maxItemsToReturn }, + token + ); + if (Array.isArray(res?.QuickFixes)) { + return res.QuickFixes.map((symbol) => this._asSymbolInformation(symbol)); + } + } catch { + /* empty */ + } + + return []; + } + + private _asSymbolInformation(symbolInfo: protocol.SymbolLocation): SymbolInformation { + let uri: Uri; + if (symbolInfo.GeneratedFileInfo) { + uri = this.sourceGeneratedDocumentProvider.addSourceGeneratedFileWithoutInitialContent( + symbolInfo.GeneratedFileInfo, + symbolInfo.FileName + ); + } else { + uri = Uri.file(symbolInfo.FileName); + } + + const location = new Location(uri, toRange(symbolInfo)); + + return new SymbolInformation( + symbolInfo.Text, + OmniSharpWorkspaceSymbolProvider._toKind(symbolInfo), + symbolInfo.ContainingSymbolName ?? '', + location + ); + } + + private static _toKind(symbolInfo: protocol.SymbolLocation): SymbolKind { + switch (symbolInfo.Kind) { + case 'Method': + return SymbolKind.Method; + case 'Field': + return SymbolKind.Field; + case 'Property': + return SymbolKind.Property; + case 'Interface': + return SymbolKind.Interface; + case 'Enum': + return SymbolKind.Enum; + case 'Struct': + return SymbolKind.Struct; + case 'Event': + return SymbolKind.Event; + case 'EnumMember': + return SymbolKind.EnumMember; + case 'Class': + return SymbolKind.Class; + default: + return SymbolKind.Class; + } + } +} diff --git a/src/omnisharp/observers/telemetryObserver.ts b/src/omnisharp/observers/telemetryObserver.ts index e3e3a89f70..2dea257571 100644 --- a/src/omnisharp/observers/telemetryObserver.ts +++ b/src/omnisharp/observers/telemetryObserver.ts @@ -66,11 +66,11 @@ export class TelemetryObserver { } case EventType.TelemetryErrorEvent: { const telemetryErrorEvent = event; + // errorProps has been ignored by @vscode/extension-telemetry since v0.6. this.reporter.sendTelemetryErrorEvent( telemetryErrorEvent.eventName, telemetryErrorEvent.properties, - telemetryErrorEvent.measures, - telemetryErrorEvent.errorProps + telemetryErrorEvent.measures ); break; } diff --git a/src/packageManager/downloadAndInstallPackages.ts b/src/packageManager/downloadAndInstallPackages.ts index e2cb5ba450..50a3698232 100644 --- a/src/packageManager/downloadAndInstallPackages.ts +++ b/src/packageManager/downloadAndInstallPackages.ts @@ -12,7 +12,7 @@ import { NetworkSettingsProvider } from '../networkSettings.ts'; import { AbsolutePathPackage } from './absolutePathPackage.ts'; import { touchInstallFile, InstallFileType, deleteInstallFile, installFileExists } from '../common.ts'; import { InstallationFailure, IntegrityCheckFailure } from '../shared/loggingEvents.ts'; -import { mkdirpSync } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { PackageInstallStart } from '../shared/loggingEvents.ts'; import { DownloadValidator } from './isValidDownload.ts'; import { CancellationToken } from 'vscode'; @@ -32,7 +32,7 @@ export async function downloadAndInstallPackages( for (const pkg of packages) { let installationStage = 'touchBeginFile'; try { - mkdirpSync(pkg.installPath.value); + fsExtra.mkdirpSync(pkg.installPath.value); await touchInstallFile(pkg.installPath, InstallFileType.Begin); let count = 1; const willTryInstallingPackage = () => count <= 2; // try 2 times diff --git a/src/packageManager/zipInstaller.ts b/src/packageManager/zipInstaller.ts index 1072c3a07a..b4314c3ec8 100644 --- a/src/packageManager/zipInstaller.ts +++ b/src/packageManager/zipInstaller.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; -import { ensureDir } from 'fs-extra'; +import fsExtra from 'fs-extra'; import * as path from 'path'; import * as yauzl from 'yauzl'; import { EventStream } from '../eventStream.ts'; @@ -38,7 +38,7 @@ export async function InstallZip( if (entry.fileName.endsWith('/')) { // Directory - create it try { - await ensureDir(absoluteEntryPath, 0o775); + await fsExtra.ensureDir(absoluteEntryPath, 0o775); zipFile.readEntry(); } catch (err) { const error = err as NodeJS.ErrnoException; // Hack for TypeScript to type err correctly @@ -54,7 +54,7 @@ export async function InstallZip( } try { - await ensureDir(path.dirname(absoluteEntryPath), 0o775); + await fsExtra.ensureDir(path.dirname(absoluteEntryPath), 0o775); // Make sure executable files have correct permissions when extracted const binaryPaths = binaries?.map((binary) => binary.value); diff --git a/src/razor/src/blazorDebug/blazorDebugConfigurationProvider.ts b/src/razor/src/blazorDebug/blazorDebugConfigurationProvider.ts index d920cb6486..ecfd131a3b 100644 --- a/src/razor/src/blazorDebug/blazorDebugConfigurationProvider.ts +++ b/src/razor/src/blazorDebug/blazorDebugConfigurationProvider.ts @@ -11,7 +11,7 @@ import * as vscode from 'vscode'; import { ChromeBrowserFinder, EdgeBrowserFinder } from '@vscode/js-debug-browsers'; import { ONLY_JS_DEBUG_NAME, MANAGED_DEBUG_NAME, JS_DEBUG_NAME, SERVER_APP_NAME } from './constants.ts'; import { isValidEvent, onDidTerminateDebugSession } from './terminateDebugHandler.ts'; -import path = require('path'); +import * as path from 'path'; import * as cp from 'child_process'; import { getExtensionPath } from '../../../common.ts'; import { getCSharpDevKit } from '../../../utils/getCSharpDevKit.ts'; @@ -22,12 +22,12 @@ import { IDotnetAcquireResult, IDotnetFindPathContext, } from '../../../lsptoolshost/dotnetRuntime/dotnetRuntimeExtensionApi.ts'; -import { IDisposable } from '@microsoft/servicehub-framework'; -import { Observer } from '@microsoft/servicehub-framework/js/src/jsonRpc/Observer'; import { EventEmitter } from 'events'; import { Formatters, + IDisposable, MessageDelimiters, + Observer, ServiceJsonRpcDescriptor, ServiceMoniker, ServiceRpcDescriptor, diff --git a/src/shared/assets.ts b/src/shared/assets.ts index dfddfb6929..3d373e2c2d 100644 --- a/src/shared/assets.ts +++ b/src/shared/assets.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as jsonc from 'jsonc-parser'; import { FormattingOptions, ModificationOptions } from 'jsonc-parser'; import * as os from 'os'; diff --git a/src/shared/dotnetConfigurationProvider.ts b/src/shared/dotnetConfigurationProvider.ts index 9984d5a6ba..798526fb95 100644 --- a/src/shared/dotnetConfigurationProvider.ts +++ b/src/shared/dotnetConfigurationProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as vscode from 'vscode'; import { IWorkspaceDebugInformationProvider, ProjectDebugInformation } from './IWorkspaceDebugInformationProvider.ts'; import { AssetGenerator, AssetOperations, addTasksJsonIfNecessary, getBuildOperations } from './assets.ts'; diff --git a/src/shared/platform.ts b/src/shared/platform.ts index 5fc09abc66..1eee6273f8 100644 --- a/src/shared/platform.ts +++ b/src/shared/platform.ts @@ -6,9 +6,11 @@ import * as crypto from 'crypto'; import * as fs from 'fs'; import * as os from 'os'; +import { fileURLToPath } from 'url'; import * as util from '../common.ts'; const unknown = 'unknown'; +const currentDirectory = fileURLToPath(new URL('.', import.meta.url)); /** * There is no standard way on Linux to find the distribution name and version. @@ -180,7 +182,7 @@ export class PlatformInformation { } private static async GetUnixArchitecture(): Promise { - const architecture = (await util.execChildProcess('uname -m', __dirname, process.env)).trim(); + const architecture = (await util.execChildProcess('uname -m', currentDirectory, process.env)).trim(); if (architecture === 'aarch64') { return 'arm64'; } @@ -190,7 +192,7 @@ export class PlatformInformation { // Emulates https://github.com/dotnet/install-scripts/blob/3c6cc06/src/dotnet-install.sh#L187-L189. private static async GetIsMusl(): Promise { try { - const output = await util.execChildProcess('ldd --version', __dirname, process.env); + const output = await util.execChildProcess('ldd --version', currentDirectory, process.env); return output.includes('musl'); } catch (err) { return err instanceof Error ? err.message.includes('musl') : false; diff --git a/src/shared/processPicker.ts b/src/shared/processPicker.ts index abad81bd42..3f58545551 100644 --- a/src/shared/processPicker.ts +++ b/src/shared/processPicker.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as child_process from 'child_process'; -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as os from 'os'; import * as path from 'path'; import * as vscode from 'vscode'; diff --git a/src/shared/projectConfiguration.ts b/src/shared/projectConfiguration.ts index ba725438fc..b1b02d5623 100644 --- a/src/shared/projectConfiguration.ts +++ b/src/shared/projectConfiguration.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as crypto from 'crypto'; -import { machineIdSync } from 'node-machine-id'; +import nodeMachineId from 'node-machine-id'; import { PlatformInformation } from './platform.ts'; import { ITelemetryReporter, getTelemetryProps } from './telemetryReporter.ts'; import { DotnetInfo } from './utils/dotnetInfo.ts'; @@ -72,7 +72,7 @@ export function reportProjectConfigurationEvent( function createSolutionId(solutionPath: string) { const solutionHash = crypto.createHash('sha256').update(solutionPath).digest('hex'); - const machineId = machineIdSync(); + const machineId = nodeMachineId.machineIdSync(); const machineHash = crypto.createHash('sha256').update(machineId).digest('hex'); return crypto diff --git a/src/shared/telemetryReporter.ts b/src/shared/telemetryReporter.ts index cfb8323bae..87890d2457 100644 --- a/src/shared/telemetryReporter.ts +++ b/src/shared/telemetryReporter.ts @@ -14,11 +14,14 @@ export interface ITelemetryReporter { sendTelemetryErrorEvent( eventName: string, properties?: { [key: string]: string }, - measures?: { [key: string]: number }, - errorProps?: string[] + measures?: { [key: string]: number } ): void; } +export interface ITelemetryReporterWithLevel extends ITelemetryReporter { + telemetryLevel: 'all' | 'error' | 'crash' | 'off'; +} + export function getTelemetryProps(platformInfo: PlatformInformation) { const telemetryProps: { [key: string]: string } = { 'platform.architecture': platformInfo.architecture, diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 7c70a1f6e7..bb762674ec 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as path from 'path'; import { parse as parseJsonc } from 'jsonc-parser'; diff --git a/src/shared/workspaceConfigurationProvider.ts b/src/shared/workspaceConfigurationProvider.ts index 60ea12b2f4..87227d03c7 100644 --- a/src/shared/workspaceConfigurationProvider.ts +++ b/src/shared/workspaceConfigurationProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as vscode from 'vscode'; import { diff --git a/tasks/compilation/bundleAudit.mjs b/tasks/compilation/bundleAudit.mjs new file mode 100644 index 0000000000..53e07e23bc --- /dev/null +++ b/tasks/compilation/bundleAudit.mjs @@ -0,0 +1,208 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import fs from 'node:fs/promises'; + +/** + * The extension is emitted as native ESM, but bundled CommonJS dependencies still use runtime + * `require()` calls and path globals such as `__dirname`. esbuild.mjs supplies compatibility + * bridges for them. This audit inspects esbuild's metafile to keep the require boundary explicit: + * + * - first-party runtime requires are rejected; + * - each dependency owner and required target must exactly match this allowlist, so new requires + * fail the build and obsolete entries must be removed; + * - the output must remain an ESM bundle that only exports `activate` and imports `vscode` as ESM. + * + * The summary identifies direct and transitive owners to make future package upgrades easier to + * evaluate. This list describes the generated bundle, not every CommonJS package in node_modules. + */ +const expectedRuntimeRequires = { + '@microsoft/servicehub-framework': ['assert', 'crypto', 'events', 'net', 'os', 'path', 'stream', 'util'], + '@vscode/js-debug-browsers': ['child_process', 'fs', 'os', 'path'], + '@vscode/l10n': ['fs', 'fs/promises'], + 'agent-base': ['http', 'https', 'net'], + archiver: ['buffer', 'events', 'fs', 'path', 'stream', 'util', 'zlib'], + 'archiver-utils': ['path', 'stream', 'util'], + bl: ['buffer', 'events', 'stream', 'util'], + 'buffer-crc32': ['buffer'], + 'compress-commons': ['buffer', 'events', 'stream', 'util'], + 'crc32-stream': ['buffer', 'events', 'stream', 'util', 'zlib'], + 'cross-spawn': ['child_process', 'fs', 'path'], + debug: ['tty', 'util'], + execa: ['child_process', 'os', 'path'], + 'fs-constants': ['constants', 'fs'], + 'fs-extra': ['path'], + 'fs.realpath': ['fs', 'path'], + 'get-stream': ['buffer', 'stream'], + glob: ['assert', 'events', 'fs', 'path', 'util'], + 'graceful-fs': ['assert', 'constants', 'fs', 'stream', 'util'], + 'http-proxy-agent': ['events', 'net', 'tls'], + 'https-proxy-agent': ['assert', 'net', 'tls'], + inherits: ['util'], + isexe: ['fs'], + jsonfile: ['fs'], + lazystream: ['util'], + 'merge-stream': ['stream'], + // Razor is a version-pinned component tarball. Update it through component servicing, not npm. + 'microsoft.aspnetcore.razor.vscode': [ + 'child_process', + 'crypto', + 'events', + 'fs', + 'net', + 'os', + 'path', + 'url', + 'util', + 'vscode', + ], + minimatch: ['path'], + 'msgpack-lite': ['stream', 'util'], + 'nerdbank-streams': ['crypto', 'events', 'stream'], + 'node-machine-id': ['child_process', 'crypto'], + 'npm-run-path': ['path'], + 'ps-list': ['child_process', 'path', 'util'], + pump: ['fs'], + 'readable-stream': ['events', 'stream', 'util'], + 'readdir-glob': ['events', 'fs', 'path'], + 'safe-buffer': ['buffer'], + 'signal-exit': ['assert', 'events'], + 'supports-color': ['os', 'tty'], + 'tar-stream': ['buffer', 'events', 'stream', 'string_decoder', 'util'], + 'util-deprecate': ['util'], + 'vscode-jsonrpc': ['crypto', 'fs', 'net', 'os', 'path', 'util'], + 'vscode-languageclient': ['child_process', 'fs', 'path', 'readline', 'vscode'], + which: ['path'], + yauzl: ['events', 'fs', 'stream', 'util', 'zlib'], + 'zip-stream': ['util'], +}; + +function getPackageOwner(inputPath) { + const normalizedPath = inputPath.replaceAll('\\', '/'); + const marker = 'node_modules/'; + const markerIndex = normalizedPath.indexOf(marker); + if (markerIndex < 0) { + return undefined; + } + + const [firstSegment, secondSegment] = normalizedPath.slice(markerIndex + marker.length).split('/'); + return firstSegment.startsWith('@') ? `${firstSegment}/${secondSegment}` : firstSegment; +} + +function getRuntimeRequires(metafile) { + const packageRequires = new Map(); + const firstPartyRequires = []; + + for (const [inputPath, input] of Object.entries(metafile.inputs)) { + for (const imported of input.imports) { + if (!imported.external || !['require-call', 'require-resolve'].includes(imported.kind)) { + continue; + } + + const packageOwner = getPackageOwner(inputPath); + if (!packageOwner) { + firstPartyRequires.push(`${inputPath} -> ${imported.path}`); + continue; + } + + let record = packageRequires.get(packageOwner); + if (!record) { + record = { imports: 0, inputs: new Set(), targets: new Set() }; + packageRequires.set(packageOwner, record); + } + + record.imports++; + record.inputs.add(inputPath); + record.targets.add(imported.path); + } + } + + return { firstPartyRequires, packageRequires }; +} + +function getDifferences(left, right) { + return [...left].filter((value) => !right.has(value)).sort(); +} + +function validateRuntimeRequires(firstPartyRequires, packageRequires) { + const issues = []; + if (firstPartyRequires.length > 0) { + issues.push(`First-party source emitted CommonJS runtime requires: ${firstPartyRequires.join(', ')}`); + } + + const expectedPackages = new Set(Object.keys(expectedRuntimeRequires)); + const actualPackages = new Set(packageRequires.keys()); + const unexpectedPackages = getDifferences(actualPackages, expectedPackages); + const stalePackages = getDifferences(expectedPackages, actualPackages); + + if (unexpectedPackages.length > 0) { + issues.push(`Review and allowlist new bridge owners: ${unexpectedPackages.join(', ')}`); + } + if (stalePackages.length > 0) { + issues.push(`Remove bridge owners that no longer require it: ${stalePackages.join(', ')}`); + } + + for (const packageName of [...expectedPackages].filter((name) => actualPackages.has(name)).sort()) { + const expectedTargets = new Set(expectedRuntimeRequires[packageName]); + const actualTargets = packageRequires.get(packageName).targets; + const addedTargets = getDifferences(actualTargets, expectedTargets); + const removedTargets = getDifferences(expectedTargets, actualTargets); + + if (addedTargets.length > 0) { + issues.push(`${packageName} added runtime requires: ${addedTargets.join(', ')}`); + } + if (removedTargets.length > 0) { + issues.push(`${packageName} no longer requires: ${removedTargets.join(', ')}`); + } + } + + if (issues.length > 0) { + throw new Error(`Bundle runtime require audit failed:\n- ${issues.join('\n- ')}`); + } +} + +function validateEsmOutput(metafile) { + const output = Object.entries(metafile.outputs).find(([outputPath]) => + outputPath.replaceAll('\\', '/').endsWith('dist/extension.mjs') + )?.[1]; + if (!output) { + throw new Error('Bundle runtime require audit could not find dist/extension.mjs in the esbuild metafile.'); + } + + if (output.exports.length !== 1 || output.exports[0] !== 'activate') { + throw new Error(`Expected the extension bundle to export only activate; found: ${output.exports.join(', ')}`); + } + + if (!output.imports.some((imported) => imported.path === 'vscode' && imported.kind === 'import-statement')) { + throw new Error('Expected the extension bundle to use a native ESM import for vscode.'); + } +} + +export async function auditBundle(metafile, production) { + if (!metafile) { + throw new Error('Bundle runtime require audit requires an esbuild metafile.'); + } + + const { firstPartyRequires, packageRequires } = getRuntimeRequires(metafile); + validateRuntimeRequires(firstPartyRequires, packageRequires); + validateEsmOutput(metafile); + + const packageJson = JSON.parse(await fs.readFile('package.json', 'utf8')); + const directDependencies = new Set(Object.keys(packageJson.dependencies)); + const packageNames = [...packageRequires.keys()].sort(); + const directOwners = packageNames.filter((name) => directDependencies.has(name)); + const transitiveOwners = packageNames.filter((name) => !directDependencies.has(name)); + const vscodeOwners = packageNames.filter((name) => packageRequires.get(name).targets.has('vscode')); + const moduleCount = new Set([...packageRequires.values()].flatMap((record) => [...record.inputs])).size; + const importCount = [...packageRequires.values()].reduce((count, record) => count + record.imports, 0); + const mode = production ? 'production' : 'development'; + + console.log( + `[bundle-audit] ${mode}: ${packageNames.length} owners, ${moduleCount} modules, ${importCount} runtime requires` + ); + console.log(`[bundle-audit] direct/component: ${directOwners.join(', ')}`); + console.log(`[bundle-audit] transitive: ${transitiveOwners.join(', ')}`); + console.log(`[bundle-audit] require("vscode"): ${vscodeOwners.join(', ')}`); +} diff --git a/tasks/packaging/offlinePackagingTasks.ts b/tasks/packaging/offlinePackagingTasks.ts index 0933a5d929..6c1e2906d6 100644 --- a/tasks/packaging/offlinePackagingTasks.ts +++ b/tasks/packaging/offlinePackagingTasks.ts @@ -5,7 +5,7 @@ import * as cp from 'child_process'; import * as fs from 'fs'; -import * as fsextra from 'fs-extra'; +import fsextra from 'fs-extra'; import * as nbgv from 'nerdbank-gitversioning'; import { Logger } from '../../src/logger.ts'; import { PlatformInformation } from '../../src/shared/platform.ts'; diff --git a/tasks/projectPaths.ts b/tasks/projectPaths.ts index 3112bb2614..9b34483b50 100644 --- a/tasks/projectPaths.ts +++ b/tasks/projectPaths.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; +import { fileURLToPath } from 'url'; import { commandLineOptions } from './commandLineArguments.ts'; import { componentInfo } from '../src/lsptoolshost/extensions/builtInComponents.ts'; -export const rootPath = path.resolve(__dirname, '..'); +export const rootPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const nodeModulesPath = path.join(rootPath, 'node_modules'); export const vscePath = path.join(nodeModulesPath, '@vscode', 'vsce', 'vsce'); diff --git a/tasks/tests/omnisharptestTasks.ts b/tasks/tests/omnisharptestTasks.ts index fb6adce7c4..ed5357b1dc 100644 --- a/tasks/tests/omnisharptestTasks.ts +++ b/tasks/tests/omnisharptestTasks.ts @@ -6,12 +6,12 @@ import path from 'path'; import { codeExtensionPath, rootPath } from '../projectPaths.ts'; import { runJestIntegrationTest, runJestTest } from './testHelpers.ts'; -import { jestOmniSharpUnitTestProjectName } from '../../test/omnisharp/omnisharpUnitTests/jest.config.ts'; +import { jestProjectNames } from '../../test/jestProjectNames.mjs'; const omnisharpIntegrationTestProjects = ['singleCsproj', 'slnWithCsproj', 'slnFilterWithCsproj', 'BasicRazorApp2_1']; export async function omnisharpTestUnit(): Promise { - await runJestTest(jestOmniSharpUnitTestProjectName); + await runJestTest(jestProjectNames.omnisharpUnit); } export async function omnisharpTestIntegration(skipLsp: boolean = false): Promise { diff --git a/tasks/tests/testHelpers.ts b/tasks/tests/testHelpers.ts index 6b2f30d7ea..4fe4782c01 100644 --- a/tasks/tests/testHelpers.ts +++ b/tasks/tests/testHelpers.ts @@ -5,7 +5,7 @@ import fs from 'fs'; import * as path from 'path'; -import * as jest from 'jest'; +import jest from 'jest'; import { Config } from '@jest/types'; import { rootPath, outPath } from '../projectPaths.ts'; import { prepareVSCodeAndExecuteTests } from '../../test/vscodeLauncher.ts'; @@ -107,7 +107,7 @@ export async function runJestIntegrationTest( throw new Error(`Could not find vscode workspace to open at ${workspacePath}`); } - // The runner (that loads in the vscode process to run tests) is in the test folder in the *output* directory. + // The ESM loader requires the explicit runner file rather than its containing directory. const vscodeRunnerPath = path.join(outPath, testFolderName, 'index.js'); if (!fs.existsSync(vscodeRunnerPath)) { throw new Error(`Could not find vscode runner in out/ at ${vscodeRunnerPath}`); @@ -147,7 +147,7 @@ export function getJUnitFileName(logName: string) { export async function runJestTest(project: string) { process.env.JEST_JUNIT_OUTPUT_NAME = getJUnitFileName(project); process.env.JEST_SUITE_NAME = project; - const configPath = path.join(rootPath, 'jest.config.ts'); + const configPath = path.join(rootPath, 'jest.config.mjs'); const { results } = await jest.runCLI( { diff --git a/tasks/tests/testTasks.ts b/tasks/tests/testTasks.ts index 3212ac3706..93f5f2c424 100644 --- a/tasks/tests/testTasks.ts +++ b/tasks/tests/testTasks.ts @@ -5,15 +5,12 @@ import path from 'path'; import { integrationTestProjects, runDevKitIntegrationTests, runIntegrationTest, runJestTest } from './testHelpers.ts'; -import { jestArtifactTestsProjectName } from '../../test/lsptoolshost/artifactTests/jest.config.ts'; -import { jestUnitTestProjectName } from '../../test/lsptoolshost/unitTests/jest.config.ts'; -import { razorTestProjectName } from '../../test/razor/razorTests/jest.config.ts'; -import { jestTasksTestProjectName } from '../../test/tasks/jest.config.ts'; +import { jestProjectNames } from '../../test/jestProjectNames.mjs'; const razorIntegrationTestProjects = ['RazorApp']; export async function testArtifacts(): Promise { - await runJestTest(jestArtifactTestsProjectName); + await runJestTest(jestProjectNames.artifact); } export async function testIntegrationCSharp(): Promise { @@ -43,7 +40,7 @@ export async function testIntegrationUntrusted(): Promise { } export async function testUnit(): Promise { - await runJestTest(jestUnitTestProjectName); - await runJestTest(razorTestProjectName); - await runJestTest(jestTasksTestProjectName); + await runJestTest(jestProjectNames.unit); + await runJestTest(jestProjectNames.razorUnit); + await runJestTest(jestProjectNames.tasksUnit); } diff --git a/test/createTmpAsset.ts b/test/createTmpAsset.ts index 36bc5f36da..f520debae9 100644 --- a/test/createTmpAsset.ts +++ b/test/createTmpAsset.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as tmp from 'tmp'; -import { remove } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { NestedError } from '../src/nestedError.ts'; export async function CreateTmpFile(): Promise { @@ -43,7 +43,7 @@ export async function CreateTmpDir(unsafeCleanup: boolean): Promise { name: tmpDir.name, dispose: () => { if (unsafeCleanup) { - remove(tmpDir.name).catch((rejectReason) => { + fsExtra.remove(tmpDir.name).catch((rejectReason) => { throw new Error(`Failed to cleanup ${tmpDir.name} at ${tmpDir.fd}: ${rejectReason}`); }); //to delete directories that have folders inside them } else { diff --git a/test/fakes.ts b/test/fakes.ts index 0a8f01cb31..35e656012c 100644 --- a/test/fakes.ts +++ b/test/fakes.ts @@ -50,8 +50,7 @@ export const getNullTelemetryReporter = (): ITelemetryReporter => { sendTelemetryErrorEvent: ( _eventName: string, _properties?: { [key: string]: string }, - _measures?: { [key: string]: number }, - _errorProps?: string[] + _measures?: { [key: string]: number } ) => { /** empty */ }, diff --git a/test/jestProjectNames.d.mts b/test/jestProjectNames.d.mts new file mode 100644 index 0000000000..64adc29abc --- /dev/null +++ b/test/jestProjectNames.d.mts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const jestProjectNames: Readonly<{ + artifact: 'Artifact Tests'; + integration: 'Integration Tests'; + omnisharpIntegration: 'OmniSharp Integration Tests'; + omnisharpUnit: 'OmniSharp Unit Tests'; + razorIntegration: 'Razor Integration Tests'; + razorUnit: 'Razor Unit Tests'; + tasksUnit: 'Tasks Unit Tests'; + unit: 'Unit Tests'; + untrustedIntegration: 'Untrusted Integration Tests'; +}>; diff --git a/test/jestProjectNames.mjs b/test/jestProjectNames.mjs new file mode 100644 index 0000000000..8b9f32ba0b --- /dev/null +++ b/test/jestProjectNames.mjs @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const jestProjectNames = Object.freeze({ + artifact: 'Artifact Tests', + integration: 'Integration Tests', + omnisharpIntegration: 'OmniSharp Integration Tests', + omnisharpUnit: 'OmniSharp Unit Tests', + razorIntegration: 'Razor Integration Tests', + razorUnit: 'Razor Unit Tests', + tasksUnit: 'Tasks Unit Tests', + unit: 'Unit Tests', + untrustedIntegration: 'Untrusted Integration Tests', +}); diff --git a/test/lsptoolshost/artifactTests/extensionBundle.test.ts b/test/lsptoolshost/artifactTests/extensionBundle.test.ts new file mode 100644 index 0000000000..270846e95c --- /dev/null +++ b/test/lsptoolshost/artifactTests/extensionBundle.test.ts @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { describe, expect, test } from '@jest/globals'; +import esbuild from 'esbuild'; +import fs from 'fs-extra'; +import path from 'node:path'; + +const packageJson = fs.readJsonSync(path.resolve('package.json')); +const extensionEntry = path.resolve(packageJson.main); + +describe('Extension bundle', () => { + test('package main points to an existing .mjs file', async () => { + expect(path.extname(packageJson.main)).toBe('.mjs'); + await expect(fs.pathExists(extensionEntry)).resolves.toBe(true); + }); + + test('entry is native ESM with the activation contract', async () => { + const result = await esbuild.build({ + entryPoints: [extensionEntry], + bundle: false, + format: 'esm', + metafile: true, + outdir: 'artifact-audit', + write: false, + }); + const output = Object.values(result.metafile.outputs)[0]; + + expect(output.exports).toEqual(['activate']); + expect(output.imports).toContainEqual({ + external: true, + kind: 'import-statement', + path: 'vscode', + }); + }); + + test('entry provides CommonJS path globals for bundled dependencies', async () => { + const contents = await fs.readFile(extensionEntry, 'utf8'); + + expect(contents).toContain(`import { dirname as __pathDirname } from 'node:path';`); + expect(contents).toContain(`import { fileURLToPath as __fileURLToPath } from 'node:url';`); + expect(contents).toContain('const __filename = __fileURLToPath(import.meta.url);'); + expect(contents).toContain('const __dirname = __pathDirname(__filename);'); + }); + + test('JavaScript signing includes .mjs output', async () => { + const signingProject = await fs.readFile(path.resolve('msbuild/signing/signJs/signJs.proj'), 'utf8'); + expect(signingProject).toContain(''); + }); +}); diff --git a/test/lsptoolshost/artifactTests/jest.config.ts b/test/lsptoolshost/artifactTests/jest.config.mjs similarity index 75% rename from test/lsptoolshost/artifactTests/jest.config.ts rename to test/lsptoolshost/artifactTests/jest.config.mjs index 8c1dbee4df..3612a32958 100644 --- a/test/lsptoolshost/artifactTests/jest.config.ts +++ b/test/lsptoolshost/artifactTests/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestArtifactTestsProjectName = 'Artifact Tests'; +import { baseProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a jest project configuration for artifact tests. */ -const unitTestConfig: Config = { +/** @type {import('jest').Config} */ +const unitTestConfig = { ...baseProjectConfig, - displayName: jestArtifactTestsProjectName, + displayName: jestProjectNames.artifact, // We need to explicity ignore the out directory for modules - otherwise we'll get duplicate vscode module, // the TS version from the __mocks__ directory and the compiled js version from the out directory. modulePathIgnorePatterns: ['out'], diff --git a/test/lsptoolshost/artifactTests/vsix.test.ts b/test/lsptoolshost/artifactTests/vsix.test.ts index 6491ee692c..038d9ae0bd 100644 --- a/test/lsptoolshost/artifactTests/vsix.test.ts +++ b/test/lsptoolshost/artifactTests/vsix.test.ts @@ -4,11 +4,38 @@ *--------------------------------------------------------------------------------------------*/ import { describe, test, expect } from '@jest/globals'; -import * as fs from 'fs-extra'; -import * as glob from 'glob'; +import fs from 'fs-extra'; +import glob from 'glob'; import * as path from 'path'; +import * as yauzl from 'yauzl'; const vsixFiles = glob.sync(path.join(process.cwd(), '**', '*.vsix')); +const packageJson = fs.readJsonSync(path.resolve('package.json')); +const extensionEntry = path.posix.join('extension', packageJson.main.replace(/^\.\//, '')); + +async function getVsixEntries(vsixPath: string): Promise { + return new Promise((resolve, reject) => { + yauzl.open(vsixPath, { lazyEntries: true }, (error, zipFile) => { + if (error) { + reject(error); + return; + } + if (!zipFile) { + reject(new Error(`Unable to open ${vsixPath}`)); + return; + } + + const entries: string[] = []; + zipFile.on('entry', (entry) => { + entries.push(entry.fileName); + zipFile.readEntry(); + }); + zipFile.on('end', () => resolve(entries)); + zipFile.on('error', reject); + zipFile.readEntry(); + }); + }); +} describe('Vscode VSIX', () => { test('At least one vsix file should be produced', () => { @@ -31,6 +58,10 @@ describe('Vscode VSIX', () => { const stats = await fs.stat(element); expect(stats.size).toBeGreaterThan(0); }); + + test('Then it should contain the declared extension entry', async () => { + await expect(getVsixEntries(element)).resolves.toContain(extensionEntry); + }); }); }); }); diff --git a/test/lsptoolshost/integrationTests/index.ts b/test/lsptoolshost/integrationTests/index.ts index 885bf3a710..9e8cfed6e4 100644 --- a/test/lsptoolshost/integrationTests/index.ts +++ b/test/lsptoolshost/integrationTests/index.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { runIntegrationTests } from '../../runIntegrationTests.ts'; -import { jestIntegrationTestProjectName } from './jest.config.ts'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; export async function run() { process.env.RUNNING_INTEGRATION_TESTS = 'true'; - await runIntegrationTests(jestIntegrationTestProjectName); + await runIntegrationTests(jestProjectNames.integration); } diff --git a/test/lsptoolshost/integrationTests/jest.config.ts b/test/lsptoolshost/integrationTests/jest.config.mjs similarity index 67% rename from test/lsptoolshost/integrationTests/jest.config.ts rename to test/lsptoolshost/integrationTests/jest.config.mjs index 7d399c45a8..73e4ef1f6d 100644 --- a/test/lsptoolshost/integrationTests/jest.config.ts +++ b/test/lsptoolshost/integrationTests/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestIntegrationTestProjectName = 'Integration Tests'; +import { baseIntegrationProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a project configuration for jest integration tests. */ -const integrationTestConfig: Config = { - ...baseProjectConfig, - displayName: jestIntegrationTestProjectName, +/** @type {import('jest').Config} */ +const integrationTestConfig = { + ...baseIntegrationProjectConfig, + displayName: jestProjectNames.integration, roots: [''], testEnvironment: '/../../vsCodeEnvironment.ts', setupFilesAfterEnv: ['/../../vsCodeFramework.ts'], diff --git a/test/lsptoolshost/integrationTests/testAssets/testAssets.ts b/test/lsptoolshost/integrationTests/testAssets/testAssets.ts index da9370d1ff..c019cfd4c5 100644 --- a/test/lsptoolshost/integrationTests/testAssets/testAssets.ts +++ b/test/lsptoolshost/integrationTests/testAssets/testAssets.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as path from 'path'; import * as vscode from 'vscode'; import spawnGit from './spawnGit.ts'; diff --git a/test/lsptoolshost/unitTests/jest.config.ts b/test/lsptoolshost/unitTests/jest.config.mjs similarity index 78% rename from test/lsptoolshost/unitTests/jest.config.ts rename to test/lsptoolshost/unitTests/jest.config.mjs index 256d315926..253a897d67 100644 --- a/test/lsptoolshost/unitTests/jest.config.ts +++ b/test/lsptoolshost/unitTests/jest.config.mjs @@ -2,17 +2,17 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestUnitTestProjectName = 'Unit Tests'; +import { baseProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a jest project configuration for unit tests. */ -const unitTestConfig: Config = { +/** @type {import('jest').Config} */ +const unitTestConfig = { ...baseProjectConfig, - displayName: jestUnitTestProjectName, + displayName: jestProjectNames.unit, + setupFilesAfterEnv: ['/../../vsCodeUnitFramework.ts'], // We need to explicity ignore the out directory for modules - otherwise we'll get duplicate vscode module, // the TS version from the __mocks__ directory and the compiled js version from the out directory. modulePathIgnorePatterns: ['out'], diff --git a/test/lsptoolshost/unitTests/migrateOptions.test.ts b/test/lsptoolshost/unitTests/migrateOptions.test.ts index e825d07296..48ec2870ac 100644 --- a/test/lsptoolshost/unitTests/migrateOptions.test.ts +++ b/test/lsptoolshost/unitTests/migrateOptions.test.ts @@ -3,23 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; -import { - dotnetAcquisitionExtensionOption, - dotnetPathOption, - IDotnetAcquisitionExistingPaths, - MigrateOptions, - migrateOptions, -} from '../../../src/shared/migrateOptions.ts'; +import { IDotnetAcquisitionExistingPaths } from '../../../src/shared/migrateOptions.ts'; import { describe, test, expect, beforeEach, jest } from '@jest/globals'; import { getVSCodeWithConfig } from '../../fakes.ts'; import { CSharpExtensionId } from '../../../src/constants/csharpExtensionId.ts'; import { ConfigurationTarget } from '../../../src/vscodeAdapter.ts'; -// Necessary when spying on module members. -jest.mock('fs', () => ({ __esModule: true, ...(jest.requireActual('fs')) })); +const mockExistsSync = jest.fn(); +jest.unstable_mockModule('fs', async () => ({ + ...(await import('node:fs')), + existsSync: mockExistsSync, +})); +const fs = await import('fs'); +const { dotnetAcquisitionExtensionOption, dotnetPathOption, MigrateOptions, migrateOptions } = + await import('../../../src/shared/migrateOptions.ts'); describe('Migrate configurations', () => { const packageJson = JSON.parse(fs.readFileSync('package.json').toString()); @@ -36,7 +35,7 @@ describe('Migrate configurations', () => { const validDotnetPath = path.join(validDotnetFolder, `dotnet${process.platform === 'win32' ? '.exe' : ''}`); beforeEach(() => { - jest.spyOn(fs, 'existsSync').mockImplementation((path) => { + mockExistsSync.mockImplementation((path) => { if (path.toString().endsWith(validDotnetPath)) { return true; } diff --git a/test/lsptoolshost/unitTests/roslynLanguageClient.test.ts b/test/lsptoolshost/unitTests/roslynLanguageClient.test.ts index 1c1faa585e..7d7000ae83 100644 --- a/test/lsptoolshost/unitTests/roslynLanguageClient.test.ts +++ b/test/lsptoolshost/unitTests/roslynLanguageClient.test.ts @@ -5,11 +5,11 @@ import { describe, expect, jest, test } from '@jest/globals'; -jest.mock('vscode-languageclient/node', () => ({ +jest.unstable_mockModule('vscode-languageclient/node', () => ({ LanguageClient: class {}, State: { Running: 2 }, })); -jest.mock('vscode-languageclient', () => ({ +jest.unstable_mockModule('vscode-languageclient', () => ({ MessageDirection: { clientToServer: 1, serverToClient: 2, @@ -18,10 +18,11 @@ jest.mock('vscode-languageclient', () => ({ ProtocolRequestType: class {}, RequestType: class {}, RequestType0: class {}, + State: { Running: 2 }, })); -import { RoslynLanguageClient } from '../../../src/lsptoolshost/server/roslynLanguageClient.ts'; -import { TelemetryEventNames } from '../../../src/shared/telemetryEventNames.ts'; +const { RoslynLanguageClient } = await import('../../../src/lsptoolshost/server/roslynLanguageClient.ts'); +const { TelemetryEventNames } = await import('../../../src/shared/telemetryEventNames.ts'); describe('RoslynLanguageClient', () => { test('shows one crash notification and emits one telemetry event per crash', () => { diff --git a/test/omnisharp/omnisharpIntegrationTests/index.ts b/test/omnisharp/omnisharpIntegrationTests/index.ts index 885bf3a710..2a4654aef7 100644 --- a/test/omnisharp/omnisharpIntegrationTests/index.ts +++ b/test/omnisharp/omnisharpIntegrationTests/index.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { runIntegrationTests } from '../../runIntegrationTests.ts'; -import { jestIntegrationTestProjectName } from './jest.config.ts'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; export async function run() { process.env.RUNNING_INTEGRATION_TESTS = 'true'; - await runIntegrationTests(jestIntegrationTestProjectName); + await runIntegrationTests(jestProjectNames.omnisharpIntegration); } diff --git a/test/omnisharp/omnisharpIntegrationTests/jest.config.ts b/test/omnisharp/omnisharpIntegrationTests/jest.config.mjs similarity index 67% rename from test/omnisharp/omnisharpIntegrationTests/jest.config.ts rename to test/omnisharp/omnisharpIntegrationTests/jest.config.mjs index 0c08590d07..0d9cf7ba47 100644 --- a/test/omnisharp/omnisharpIntegrationTests/jest.config.ts +++ b/test/omnisharp/omnisharpIntegrationTests/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestIntegrationTestProjectName = 'OmniSharp Integration Tests'; +import { baseIntegrationProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a project configuration for jest integration tests. */ -const integrationTestConfig: Config = { - ...baseProjectConfig, - displayName: jestIntegrationTestProjectName, +/** @type {import('jest').Config} */ +const integrationTestConfig = { + ...baseIntegrationProjectConfig, + displayName: jestProjectNames.omnisharpIntegration, roots: [''], testEnvironment: '/../../vsCodeEnvironment.ts', setupFilesAfterEnv: ['/../../vsCodeFramework.ts'], diff --git a/test/omnisharp/omnisharpIntegrationTests/launchConfiguration.integration.test.ts b/test/omnisharp/omnisharpIntegrationTests/launchConfiguration.integration.test.ts index 8610400fd7..bc0c585bd3 100644 --- a/test/omnisharp/omnisharpIntegrationTests/launchConfiguration.integration.test.ts +++ b/test/omnisharp/omnisharpIntegrationTests/launchConfiguration.integration.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { describe, expect, test, beforeAll, afterAll } from '@jest/globals'; -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as vscode from 'vscode'; import { activateCSharpExtension } from './integrationHelpers.ts'; import testAssetWorkspace from './testAssets/activeTestAssetWorkspace.ts'; diff --git a/test/omnisharp/omnisharpUnitTests/blazorWebAssemblyDetection.test.ts b/test/omnisharp/omnisharpUnitTests/blazorWebAssemblyDetection.test.ts index 5f7c303af9..a3222c014e 100644 --- a/test/omnisharp/omnisharpUnitTests/blazorWebAssemblyDetection.test.ts +++ b/test/omnisharp/omnisharpUnitTests/blazorWebAssemblyDetection.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { describe, test, expect, beforeEach, afterEach } from '@jest/globals'; -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as path from 'path'; import { CreateTmpDir, TmpAsset } from '../../createTmpAsset.ts'; import { diff --git a/test/omnisharp/omnisharpUnitTests/jest.config.ts b/test/omnisharp/omnisharpUnitTests/jest.config.mjs similarity index 77% rename from test/omnisharp/omnisharpUnitTests/jest.config.ts rename to test/omnisharp/omnisharpUnitTests/jest.config.mjs index 6654b0d413..bd56e7bbd7 100644 --- a/test/omnisharp/omnisharpUnitTests/jest.config.ts +++ b/test/omnisharp/omnisharpUnitTests/jest.config.mjs @@ -2,17 +2,17 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestOmniSharpUnitTestProjectName = 'OmniSharp Unit Tests'; +import { baseProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a jest project configuration for O# jest tests. */ -const omnisharpConfig: Config = { +/** @type {import('jest').Config} */ +const omnisharpConfig = { ...baseProjectConfig, - displayName: jestOmniSharpUnitTestProjectName, + displayName: jestProjectNames.omnisharpUnit, + setupFilesAfterEnv: ['/../../vsCodeUnitFramework.ts'], // We need to explicity ignore the out directory for modules - otherwise we'll get duplicate vscode module, // the TS version from the __mocks__ directory and the compiled js version from the out directory. modulePathIgnorePatterns: ['out'], diff --git a/test/omnisharp/omnisharpUnitTests/logging/telemetryObserver.test.ts b/test/omnisharp/omnisharpUnitTests/logging/telemetryObserver.test.ts index 61d59482e4..885a51e5bf 100644 --- a/test/omnisharp/omnisharpUnitTests/logging/telemetryObserver.test.ts +++ b/test/omnisharp/omnisharpUnitTests/logging/telemetryObserver.test.ts @@ -26,7 +26,6 @@ describe('TelemetryReporterObserver', () => { let name = ''; let property: { [key: string]: string } | undefined = undefined; let measure: { [key: string]: number }[] = []; - let errorProp: string[] = []; const useModernNet = true; const observer = new TelemetryObserver( platformInfo, @@ -45,15 +44,11 @@ describe('TelemetryReporterObserver', () => { sendTelemetryErrorEvent: ( eventName: string, properties?: { [key: string]: string }, - measures?: { [key: string]: number }, - errorProps?: string[] + measures?: { [key: string]: number } ) => { name += eventName; property = properties; measure.push(measures!); - errorProps!.forEach((prop) => { - errorProp.push(prop); - }); }, }; }, @@ -64,7 +59,6 @@ describe('TelemetryReporterObserver', () => { name = ''; property = undefined; measure = []; - errorProp = []; }); test('PackageInstallation: AcquisitionStart is reported', async () => { @@ -141,13 +135,12 @@ describe('TelemetryReporterObserver', () => { expect(property).toEqual(event.properties); }); - test(`${TelemetryErrorEvent.name}: SendTelemetry error event is called with the name, properties, measures, and errorProps`, async () => { + test(`${TelemetryErrorEvent.name}: SendTelemetry error event is called with the name, properties, and measures`, async () => { const event = new TelemetryErrorEvent('someName', { key: 'value' }, { someKey: 1 }, ['StackTrace']); await observer.post(event); expect(name).toContain(event.eventName); expect(measure).toMatchObject([event.measures!]); expect(property).toEqual(event.properties); - expect(errorProp).toEqual(event.errorProps!); }); describe('InstallationFailure', () => { diff --git a/test/omnisharp/omnisharpUnitTests/packages/packageFilterer.test.ts b/test/omnisharp/omnisharpUnitTests/packages/packageFilterer.test.ts index e26d03c84e..63dc208127 100644 --- a/test/omnisharp/omnisharpUnitTests/packages/packageFilterer.test.ts +++ b/test/omnisharp/omnisharpUnitTests/packages/packageFilterer.test.ts @@ -3,19 +3,25 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { describe, test, expect, beforeEach, jest } from '@jest/globals'; -import { PlatformInformation } from '../../../../src/shared/platform.ts'; -import { getNotInstalledPackagesForPlatform } from '../../../../src/packageManager/packageFilterer.ts'; import { Package } from '../../../../src/packageManager/package.ts'; -import { AbsolutePathPackage } from '../../../../src/packageManager/absolutePathPackage.ts'; +import type { AbsolutePathPackage as AbsolutePathPackageType } from '../../../../src/packageManager/absolutePathPackage.ts'; import { MockedFunction } from 'jest-mock'; -import * as fs from 'fs'; +import type * as fs from 'fs'; import { join } from 'path'; -// Necessary when spying on module members. -jest.mock('fs', () => ({ __esModule: true, ...(jest.requireActual('fs')) })); +const mockStat = jest.fn() as unknown as MockedFunction< + (path: fs.PathLike, callback: (err: NodeJS.ErrnoException | null, stats: fs.Stats | undefined) => void) => void +>; +jest.unstable_mockModule('fs', async () => ({ + ...(await import('node:fs')), + stat: mockStat, +})); +const { PlatformInformation } = await import('../../../../src/shared/platform.ts'); +const { getNotInstalledPackagesForPlatform } = await import('../../../../src/packageManager/packageFilterer.ts'); +const { AbsolutePathPackage } = await import('../../../../src/packageManager/absolutePathPackage.ts'); describe(`${getNotInstalledPackagesForPlatform.name}`, () => { - let absolutePathPackages: AbsolutePathPackage[]; + let absolutePathPackages: AbsolutePathPackageType[]; const extensionPath = '/ExtensionPath'; const packages = [ { @@ -79,13 +85,7 @@ describe(`${getNotInstalledPackagesForPlatform.name}`, () => { absolutePathPackages = packages.map((pkg) => AbsolutePathPackage.getAbsolutePathPackage(pkg, extensionPath)); const installLockPath = join(absolutePathPackages[1].installPath.value, 'install.Lock'); //mock the install lock path so the package should be filtered - const statSpy = jest.spyOn(fs, 'stat') as unknown as MockedFunction< - ( - path: fs.PathLike, - callback: (err: NodeJS.ErrnoException | null, stats: fs.Stats | undefined) => void - ) => void - >; - statSpy.mockImplementation((path, callback) => { + mockStat.mockImplementation((path, callback) => { if (installLockPath === path) { callback(null, { isFile: () => true } as unknown as fs.Stats); } else { diff --git a/test/omnisharp/omnisharpUnitTests/packages/zipInstaller.test.ts b/test/omnisharp/omnisharpUnitTests/packages/zipInstaller.test.ts index 6230a59f03..fac2d3481d 100644 --- a/test/omnisharp/omnisharpUnitTests/packages/zipInstaller.test.ts +++ b/test/omnisharp/omnisharpUnitTests/packages/zipInstaller.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { describe, test, expect, beforeEach, afterEach } from '@jest/globals'; -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import * as path from 'path'; import * as util from '../../../../src/common.ts'; import { CreateTmpDir, TmpAsset } from '../../../createTmpAsset.ts'; diff --git a/test/omnisharp/omnisharpUnitTests/testAssets/mockHttpsServer.ts b/test/omnisharp/omnisharpUnitTests/testAssets/mockHttpsServer.ts index 3dafd8e9cb..92e8942e2c 100644 --- a/test/omnisharp/omnisharpUnitTests/testAssets/mockHttpsServer.ts +++ b/test/omnisharp/omnisharpUnitTests/testAssets/mockHttpsServer.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs-extra'; +import fs from 'fs-extra'; import getPort from 'get-port'; +import { createRequire } from 'node:module'; -// There are no typings for this library. -// eslint-disable-next-line @typescript-eslint/no-var-requires +// mock-http-server is CommonJS-only and has no type declarations. +const require = createRequire(import.meta.url); const ServerMock = require('mock-http-server'); export default class MockHttpsServer { diff --git a/test/omnisharp/runFeatureTests.ts b/test/omnisharp/runFeatureTests.ts index ac23047302..104d7a1ca3 100644 --- a/test/omnisharp/runFeatureTests.ts +++ b/test/omnisharp/runFeatureTests.ts @@ -4,17 +4,19 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; +import { fileURLToPath } from 'url'; import { runTests } from '@vscode/test-electron'; async function main() { try { + const currentDirectory = path.dirname(fileURLToPath(import.meta.url)); // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../'); + const extensionDevelopmentPath = path.resolve(currentDirectory, '../../'); // The path to the extension test runner script // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './omnisharpFeatureTests/index'); + const extensionTestsPath = path.resolve(currentDirectory, './omnisharpFeatureTests/index'); // Download VS Code, unzip it and run the integration test const exitCode = await runTests({ diff --git a/test/razor/razorIntegrationTests/index.ts b/test/razor/razorIntegrationTests/index.ts index 885bf3a710..a229e0117e 100644 --- a/test/razor/razorIntegrationTests/index.ts +++ b/test/razor/razorIntegrationTests/index.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { runIntegrationTests } from '../../runIntegrationTests.ts'; -import { jestIntegrationTestProjectName } from './jest.config.ts'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; export async function run() { process.env.RUNNING_INTEGRATION_TESTS = 'true'; - await runIntegrationTests(jestIntegrationTestProjectName); + await runIntegrationTests(jestProjectNames.razorIntegration); } diff --git a/test/untrustedWorkspace/integrationTests/jest.config.ts b/test/razor/razorIntegrationTests/jest.config.mjs similarity index 67% rename from test/untrustedWorkspace/integrationTests/jest.config.ts rename to test/razor/razorIntegrationTests/jest.config.mjs index 16220f0ea6..c2e634c872 100644 --- a/test/untrustedWorkspace/integrationTests/jest.config.ts +++ b/test/razor/razorIntegrationTests/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestIntegrationTestProjectName = 'Untrusted Integration Tests'; +import { baseIntegrationProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a project configuration for jest integration tests. */ -const integrationTestConfig: Config = { - ...baseProjectConfig, - displayName: jestIntegrationTestProjectName, +/** @type {import('jest').Config} */ +const integrationTestConfig = { + ...baseIntegrationProjectConfig, + displayName: jestProjectNames.razorIntegration, roots: [''], testEnvironment: '/../../vsCodeEnvironment.ts', setupFilesAfterEnv: ['/../../vsCodeFramework.ts'], diff --git a/test/razor/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/infrastructure/tokenizedContentProvider.ts b/test/razor/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/infrastructure/tokenizedContentProvider.ts index b10bcaf568..8fb41c639c 100644 --- a/test/razor/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/infrastructure/tokenizedContentProvider.ts +++ b/test/razor/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/infrastructure/tokenizedContentProvider.ts @@ -5,14 +5,20 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as oniguruma from 'vscode-oniguruma'; -import { IGrammar, INITIAL, IRawGrammar, ITokenizeLineResult, parseRawGrammar, Registry } from 'vscode-textmate'; +import { fileURLToPath } from 'url'; +import oniguruma from 'vscode-oniguruma'; +import vscodeTextmate from 'vscode-textmate'; +import type { IGrammar, IRawGrammar, ITokenizeLineResult } from 'vscode-textmate'; import { ITokenizedContent } from './ITokenizedContent.ts'; +const { INITIAL, parseRawGrammar, Registry } = vscodeTextmate; let razorGrammarCache: IGrammar | undefined; const wasmBin = fs.readFileSync( - path.join(__dirname, '../../../../../../node_modules/vscode-oniguruma/release/onig.wasm') + path.join( + path.dirname(fileURLToPath(import.meta.url)), + '../../../../../../node_modules/vscode-oniguruma/release/onig.wasm' + ) ).buffer; const vscodeOnigurumaLib = oniguruma.loadWASM(wasmBin).then(() => { return { diff --git a/test/razor/razorTests/jest.config.ts b/test/razor/razorTests/jest.config.mjs similarity index 77% rename from test/razor/razorTests/jest.config.ts rename to test/razor/razorTests/jest.config.mjs index c77606deb7..599a3311c0 100644 --- a/test/razor/razorTests/jest.config.ts +++ b/test/razor/razorTests/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const razorTestProjectName = 'Razor Unit Tests'; +import { baseProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a jest project configuration for Razor jest tests. */ -const razorConfig: Config = { +/** @type {import('jest').Config} */ +const razorConfig = { ...baseProjectConfig, - displayName: razorTestProjectName, + displayName: jestProjectNames.razorUnit, // We need to explicity ignore the out directory for modules - otherwise we'll get duplicate vscode module, // the TS version from the __mocks__ directory and the compiled js version from the out directory. modulePathIgnorePatterns: ['out'], diff --git a/test/runIntegrationTests.ts b/test/runIntegrationTests.ts index 7acedc7156..4a2906e922 100644 --- a/test/runIntegrationTests.ts +++ b/test/runIntegrationTests.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as jest from 'jest'; +import jest from 'jest'; import { Config } from '@jest/types'; import * as path from 'path'; @@ -13,7 +13,7 @@ export async function runIntegrationTests(projectName: string) { throw new Error('CODE_EXTENSIONS_PATH not set.'); } - const jestConfigPath = path.join(repoRoot, 'jest.config.ts'); + const jestConfigPath = path.join(repoRoot, 'jest.config.mjs'); const jestConfig = { config: jestConfigPath, selectProjects: [projectName], diff --git a/test/tasks/bundleAudit.test.js b/test/tasks/bundleAudit.test.js new file mode 100644 index 0000000000..5ada00d4b9 --- /dev/null +++ b/test/tasks/bundleAudit.test.js @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { expect, test } from '@jest/globals'; +import { auditBundle } from '../../tasks/compilation/bundleAudit.mjs'; + +test('bundle audit rejects first-party CommonJS runtime requires', async () => { + const metafile = { + inputs: { + 'src/unexpected.ts': { + imports: [{ external: true, kind: 'require-call', path: 'node:fs' }], + }, + }, + outputs: { + 'dist/extension.mjs': { + exports: ['activate'], + imports: [{ external: true, kind: 'import-statement', path: 'vscode' }], + }, + }, + }; + + await expect(auditBundle(metafile, false)).rejects.toThrow( + 'First-party source emitted CommonJS runtime requires: src/unexpected.ts -> node:fs' + ); +}); diff --git a/test/tasks/jest.config.ts b/test/tasks/jest.config.mjs similarity index 71% rename from test/tasks/jest.config.ts rename to test/tasks/jest.config.mjs index 9dd20c697c..e2c63f9df2 100644 --- a/test/tasks/jest.config.ts +++ b/test/tasks/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../baseJestConfig.ts'; - -export const jestTasksTestProjectName = 'Tasks Unit Tests'; +import { baseProjectConfig } from '../../baseJestConfig.mjs'; +import { jestProjectNames } from '../jestProjectNames.mjs'; /** * Defines a jest project configuration for tasks unit tests. */ -const tasksTestConfig: Config = { +/** @type {import('jest').Config} */ +const tasksTestConfig = { ...baseProjectConfig, - displayName: jestTasksTestProjectName, + displayName: jestProjectNames.tasksUnit, modulePathIgnorePatterns: ['out'], roots: ['', '../../__mocks__'], }; diff --git a/test/untrustedWorkspace/integrationTests/index.ts b/test/untrustedWorkspace/integrationTests/index.ts index 885bf3a710..09032c55de 100644 --- a/test/untrustedWorkspace/integrationTests/index.ts +++ b/test/untrustedWorkspace/integrationTests/index.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { runIntegrationTests } from '../../runIntegrationTests.ts'; -import { jestIntegrationTestProjectName } from './jest.config.ts'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; export async function run() { process.env.RUNNING_INTEGRATION_TESTS = 'true'; - await runIntegrationTests(jestIntegrationTestProjectName); + await runIntegrationTests(jestProjectNames.untrustedIntegration); } diff --git a/test/razor/razorIntegrationTests/jest.config.ts b/test/untrustedWorkspace/integrationTests/jest.config.mjs similarity index 67% rename from test/razor/razorIntegrationTests/jest.config.ts rename to test/untrustedWorkspace/integrationTests/jest.config.mjs index 9f34af5fa7..7e85705ec7 100644 --- a/test/razor/razorIntegrationTests/jest.config.ts +++ b/test/untrustedWorkspace/integrationTests/jest.config.mjs @@ -2,17 +2,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { Config } from 'jest'; -import { baseProjectConfig } from '../../../baseJestConfig.ts'; - -export const jestIntegrationTestProjectName = 'Razor Integration Tests'; +import { baseIntegrationProjectConfig } from '../../../baseJestConfig.mjs'; +import { jestProjectNames } from '../../jestProjectNames.mjs'; /** * Defines a project configuration for jest integration tests. */ -const integrationTestConfig: Config = { - ...baseProjectConfig, - displayName: jestIntegrationTestProjectName, +/** @type {import('jest').Config} */ +const integrationTestConfig = { + ...baseIntegrationProjectConfig, + displayName: jestProjectNames.untrustedIntegration, roots: [''], testEnvironment: '/../../vsCodeEnvironment.ts', setupFilesAfterEnv: ['/../../vsCodeFramework.ts'], diff --git a/test/vsCodeEnvironment.ts b/test/vsCodeEnvironment.ts index 0c886c1164..4d727493bb 100644 --- a/test/vsCodeEnvironment.ts +++ b/test/vsCodeEnvironment.ts @@ -27,4 +27,4 @@ class VsCodeEnvironment extends TestEnvironment { } } -module.exports = VsCodeEnvironment; +export default VsCodeEnvironment; diff --git a/test/vsCodeFramework.ts b/test/vsCodeFramework.ts index 816be12031..4c791b7741 100644 --- a/test/vsCodeFramework.ts +++ b/test/vsCodeFramework.ts @@ -7,3 +7,4 @@ import { jest } from '@jest/globals'; // Defines a virtual mock for the vscode library since it doesn't exist until it gets loaded in by the vscode extension process. jest.mock('vscode', () => (global as any).vscode, { virtual: true }); +jest.unstable_mockModule('vscode', () => (global as any).vscode, { virtual: true }); diff --git a/test/vsCodeUnitFramework.ts b/test/vsCodeUnitFramework.ts new file mode 100644 index 0000000000..2d44262306 --- /dev/null +++ b/test/vsCodeUnitFramework.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import { jest } from '@jest/globals'; +import * as mockVsCode from '../__mocks__/vscode.ts'; + +jest.mock('vscode', () => mockVsCode, { virtual: true }); +jest.unstable_mockModule('vscode', () => mockVsCode, { virtual: true }); diff --git a/tsconfig.jest.json b/tsconfig.jest.json new file mode 100644 index 0000000000..e20794f4bf --- /dev/null +++ b/tsconfig.jest.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "moduleResolution": "Node" + } +} diff --git a/tsconfig.json b/tsconfig.json index 49d11030dd..489935b5e3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "esModuleInterop": true, "target": "ES2022", - "module": "CommonJS", + "module": "NodeNext", "outDir": "out", "lib": [ "ES2021", @@ -28,25 +28,26 @@ "vscode-jsonrpc/node": ["./node_modules/vscode-jsonrpc/lib/node/main"], }, "sourceMap": true, - "moduleResolution": "node", + "moduleResolution": "NodeNext", "moduleDetection": "force", + "allowJs": true, "rewriteRelativeImportExtensions": true, + "isolatedModules": true, "strict": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, "noUnusedLocals": true, "noFallthroughCasesInSwitch": true }, - "ts-node": { - "experimentalResolver": true - }, + "files": [ + "test/jestProjectNames.mjs", + "test/jestProjectNames.d.mts", + ], "include": [ - "src", - "tasks", - "test", - "typings", - "__mocks__", - "jest.config.ts", - "baseJestConfig.ts", + "src/**/*.ts", + "tasks/**/*.ts", + "test/**/*.ts", + "typings/**/*.ts", + "__mocks__/**/*.ts", ], } diff --git a/wallaby.js b/wallaby.js index 2f854e80bd..fb2c0313b6 100644 --- a/wallaby.js +++ b/wallaby.js @@ -1,20 +1,20 @@ -module.exports = function(_wallaby) { - return { - env: { - type: "node" - }, - files: [ - "src/**/*.ts*", - "src/**/*.css", - "test/omnisharp/omnisharpUnitTests/**/*.ts*", - "!test/omnisharp/omnisharpUnitTests/**/*.test.ts*" - ], - tests: ["test/omnisharp/omnisharpUnitTests/**/*.test.ts*"], +export default function (_wallaby) { + return { + env: { + type: 'node', + }, + files: [ + 'src/**/*.ts*', + 'src/**/*.css', + 'test/omnisharp/omnisharpUnitTests/**/*.ts*', + '!test/omnisharp/omnisharpUnitTests/**/*.test.ts*', + ], + tests: ['test/omnisharp/omnisharpUnitTests/**/*.test.ts*'], - debug: true, + debug: true, - setup: function(wallaby) { - wallaby.testFramework.ui("tdd"); - } - }; -}; + setup(wallaby) { + wallaby.testFramework.ui('tdd'); + }, + }; +}