Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit cac3e6a

Browse files
Merge pull request #627 from codestoryai/fetch-upstream-200524
Fetch upstream 200524
2 parents 404621e + 5d0bfc9 commit cac3e6a

File tree

1,059 files changed

+142299
-18075
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,059 files changed

+142299
-18075
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as eslint from 'eslint';
7+
import { TSESTree } from '@typescript-eslint/experimental-utils';
8+
9+
export = new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule {
10+
11+
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
12+
// Disable in tests for now
13+
if (context.getFilename().includes('.test')) {
14+
return {};
15+
}
16+
17+
return {
18+
// Disallow type assertions on object literals: <T>{ ... } or {} as T
19+
['TSTypeAssertion > ObjectExpression, TSAsExpression > ObjectExpression']: (node: any) => {
20+
const objectNode = node as TSESTree.Node;
21+
22+
const parent = objectNode.parent as TSESTree.TSTypeAssertion | TSESTree.TSAsExpression;
23+
if (
24+
// Allow `as const` assertions
25+
(parent.typeAnnotation.type === 'TSTypeReference' && parent.typeAnnotation.typeName.type === 'Identifier' && parent.typeAnnotation.typeName.name === 'const')
26+
27+
// For also now still allow `any` casts
28+
|| (parent.typeAnnotation.type === 'TSAnyKeyword')
29+
) {
30+
return;
31+
}
32+
33+
context.report({
34+
node,
35+
message: "Don't use type assertions for creating objects as this can hide type errors."
36+
});
37+
},
38+
};
39+
}
40+
};

.eslintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"local/code-parameter-properties-must-have-explicit-accessibility": "warn",
7474
"local/code-no-nls-in-standalone-editor": "warn",
7575
"local/code-no-potentially-unsafe-disposables": "warn",
76+
"local/code-no-dangerous-type-assertions": "off",
7677
"local/code-no-standalone-editor": "warn",
7778
"local/code-no-unexternalized-strings": "warn",
7879
"local/code-must-use-super-dispose": "warn",
@@ -671,7 +672,6 @@
671672
"vscode-regexpp",
672673
"vscode-textmate",
673674
"worker_threads",
674-
"@xterm/addon-canvas",
675675
"@xterm/addon-image",
676676
"@xterm/addon-search",
677677
"@xterm/addon-serialize",

.nvmrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
18.19.0
1+
20.12.1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"configurations": [
3+
{
4+
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--enable-proposed-api=ms-vscode.vscode-selfhost-test-provider"],
5+
"name": "Launch Extension",
6+
"outFiles": ["${workspaceFolder}/out/**/*.js"],
7+
"request": "launch",
8+
"type": "extensionHost"
9+
}
10+
]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.defaultFormatter": "vscode.typescript-language-features",
4+
"editor.codeActionsOnSave": {
5+
"source.organizeImports": "always"
6+
}
7+
}

.vscode/extensions/vscode-selfhost-test-provider/package.json

+13-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"displayName": "VS Code Selfhost Test Provider",
44
"description": "Test provider for the VS Code project",
55
"enabledApiProposals": [
6-
"testObserver"
6+
"testObserver",
7+
"attributableCoverage"
78
],
89
"engines": {
910
"vscode": "^1.88.0"
@@ -13,6 +14,13 @@
1314
{
1415
"command": "selfhost-test-provider.updateSnapshot",
1516
"title": "Update Snapshot",
17+
"category": "Testing",
18+
"icon": "$(merge)"
19+
},
20+
{
21+
"command": "selfhost-test-provider.openFailureLog",
22+
"title": "Open Selfhost Failure Logs",
23+
"category": "Testing",
1624
"icon": "$(merge)"
1725
}
1826
],
@@ -65,10 +73,12 @@
6573
"license": "MIT",
6674
"scripts": {
6775
"compile": "gulp compile-extension:vscode-selfhost-test-provider",
68-
"watch": "gulp watch-extension:vscode-selfhost-test-provider"
76+
"watch": "gulp watch-extension:vscode-selfhost-test-provider",
77+
"test": "npx mocha --ui tdd 'out/*.test.js'"
6978
},
7079
"devDependencies": {
71-
"@types/node": "18.x"
80+
"@types/mocha": "^10.0.6",
81+
"@types/node": "20.x"
7282
},
7383
"dependencies": {
7484
"@jridgewell/trace-mapping": "^0.3.25",

.vscode/extensions/vscode-selfhost-test-provider/src/coverageProvider.ts

+150-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,154 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { IstanbulCoverageContext } from 'istanbul-to-vscode';
7+
import * as vscode from 'vscode';
8+
import { SourceLocationMapper, SourceMapStore } from './testOutputScanner';
9+
import { IScriptCoverage, OffsetToPosition, RangeCoverageTracker } from './v8CoverageWrangling';
710

8-
export const coverageContext = new IstanbulCoverageContext();
11+
export const istanbulCoverageContext = new IstanbulCoverageContext();
12+
13+
/**
14+
* Tracks coverage in per-script coverage mode. There are two modes of coverage
15+
* in this extension: generic istanbul reports, and reports from the runtime
16+
* sent before and after each test case executes. This handles the latter.
17+
*/
18+
export class PerTestCoverageTracker {
19+
private readonly scripts = new Map</* script ID */ string, Script>();
20+
21+
constructor(private readonly maps: SourceMapStore) {}
22+
23+
public add(coverage: IScriptCoverage, test?: vscode.TestItem) {
24+
const script = this.scripts.get(coverage.scriptId);
25+
if (script) {
26+
return script.add(coverage, test);
27+
}
28+
// ignore internals and node_modules
29+
if (!coverage.url.startsWith('file://') || coverage.url.includes('node_modules')) {
30+
return;
31+
}
32+
if (!coverage.source) {
33+
throw new Error('expected to have source the first time a script is seen');
34+
}
35+
36+
const src = new Script(vscode.Uri.parse(coverage.url), coverage.source, this.maps);
37+
this.scripts.set(coverage.scriptId, src);
38+
src.add(coverage, test);
39+
}
40+
41+
public async report(run: vscode.TestRun) {
42+
await Promise.all(Array.from(this.scripts.values()).map(s => s.report(run)));
43+
}
44+
}
45+
46+
class Script {
47+
private converter: OffsetToPosition;
48+
49+
/** Tracking the overall coverage for the file */
50+
private overall = new ScriptCoverageTracker();
51+
/** Range tracking per-test item */
52+
private readonly perItem = new Map<vscode.TestItem, ScriptCoverageTracker>();
53+
54+
constructor(
55+
public readonly uri: vscode.Uri,
56+
source: string,
57+
private readonly maps: SourceMapStore
58+
) {
59+
this.converter = new OffsetToPosition(source);
60+
}
61+
62+
public add(coverage: IScriptCoverage, test?: vscode.TestItem) {
63+
this.overall.add(coverage);
64+
if (test) {
65+
const p = new ScriptCoverageTracker();
66+
p.add(coverage);
67+
this.perItem.set(test, p);
68+
}
69+
}
70+
71+
public async report(run: vscode.TestRun) {
72+
const mapper = await this.maps.getSourceLocationMapper(this.uri.toString());
73+
const originalUri = (await this.maps.getSourceFile(this.uri.toString())) || this.uri;
74+
75+
run.addCoverage(this.overall.report(originalUri, this.converter, mapper));
76+
for (const [test, projection] of this.perItem) {
77+
run.addCoverage(projection.report(originalUri, this.converter, mapper, test));
78+
}
79+
}
80+
}
81+
82+
class ScriptCoverageTracker {
83+
private coverage = new RangeCoverageTracker();
84+
85+
public add(coverage: IScriptCoverage) {
86+
for (const range of RangeCoverageTracker.initializeBlocks(coverage.functions)) {
87+
this.coverage.setCovered(range.start, range.end, range.covered);
88+
}
89+
}
90+
91+
/**
92+
* Generates the script's coverage for the test run.
93+
*
94+
* If a source location mapper is given, it assumes the `uri` is the mapped
95+
* URI, and that any unmapped locations/outside the URI should be ignored.
96+
*/
97+
public report(
98+
uri: vscode.Uri,
99+
convert: OffsetToPosition,
100+
mapper: SourceLocationMapper | undefined,
101+
item?: vscode.TestItem
102+
): V8CoverageFile {
103+
const file = new V8CoverageFile(uri, item);
104+
105+
for (const range of this.coverage) {
106+
if (range.start === range.end) {
107+
continue;
108+
}
109+
110+
const startCov = convert.toLineColumn(range.start);
111+
let start = new vscode.Position(startCov.line, startCov.column);
112+
113+
const endCov = convert.toLineColumn(range.end);
114+
let end = new vscode.Position(endCov.line, endCov.column);
115+
if (mapper) {
116+
const startMap = mapper(start.line, start.character);
117+
const endMap = startMap && mapper(end.line, end.character);
118+
if (!endMap || uri.toString().toLowerCase() !== endMap.uri.toString().toLowerCase()) {
119+
continue;
120+
}
121+
start = startMap.range.start;
122+
end = endMap.range.end;
123+
}
124+
125+
for (let i = start.line; i <= end.line; i++) {
126+
file.add(
127+
new vscode.StatementCoverage(
128+
range.covered,
129+
new vscode.Range(
130+
new vscode.Position(i, i === start.line ? start.character : 0),
131+
new vscode.Position(i, i === end.line ? end.character : Number.MAX_SAFE_INTEGER)
132+
)
133+
)
134+
);
135+
}
136+
}
137+
138+
return file;
139+
}
140+
}
141+
142+
export class V8CoverageFile extends vscode.FileCoverage {
143+
public details: vscode.StatementCoverage[] = [];
144+
145+
constructor(uri: vscode.Uri, item?: vscode.TestItem) {
146+
super(uri, { covered: 0, total: 0 });
147+
(this as vscode.FileCoverage2).testItem = item;
148+
}
149+
150+
public add(detail: vscode.StatementCoverage) {
151+
this.details.push(detail);
152+
this.statementCoverage.total++;
153+
if (detail.executed) {
154+
this.statementCoverage.covered++;
155+
}
156+
}
157+
}

.vscode/extensions/vscode-selfhost-test-provider/src/extension.ts

+34-15
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { randomBytes } from 'crypto';
77
import { tmpdir } from 'os';
88
import * as path from 'path';
99
import * as vscode from 'vscode';
10-
import { coverageContext } from './coverageProvider';
10+
import { V8CoverageFile } from './coverageProvider';
1111
import { FailingDeepStrictEqualAssertFixer } from './failingDeepStrictEqualAssertFixer';
12+
import { FailureTracker } from './failureTracker';
1213
import { registerSnapshotUpdate } from './snapshot';
1314
import { scanTestOutput } from './testOutputScanner';
1415
import {
@@ -24,7 +25,7 @@ const TEST_FILE_PATTERN = 'src/vs/**/*.{test,integrationTest}.ts';
2425

2526
const getWorkspaceFolderForTestFile = (uri: vscode.Uri) =>
2627
(uri.path.endsWith('.test.ts') || uri.path.endsWith('.integrationTest.ts')) &&
27-
uri.path.includes('/src/vs/')
28+
uri.path.includes('/src/vs/')
2829
? vscode.workspace.getWorkspaceFolder(uri)
2930
: undefined;
3031

@@ -54,8 +55,14 @@ export async function activate(context: vscode.ExtensionContext) {
5455
}
5556
};
5657

58+
guessWorkspaceFolder().then(folder => {
59+
if (folder) {
60+
context.subscriptions.push(new FailureTracker(context, folder.uri.fsPath));
61+
}
62+
});
63+
5764
const createRunHandler = (
58-
runnerCtor: { new(folder: vscode.WorkspaceFolder): VSCodeTestRunner },
65+
runnerCtor: { new (folder: vscode.WorkspaceFolder): VSCodeTestRunner },
5966
kind: vscode.TestRunProfileKind,
6067
args: string[] = []
6168
) => {
@@ -78,17 +85,23 @@ export async function activate(context: vscode.ExtensionContext) {
7885
let coverageDir: string | undefined;
7986
let currentArgs = args;
8087
if (kind === vscode.TestRunProfileKind.Coverage) {
81-
coverageDir = path.join(tmpdir(), `vscode-test-coverage-${randomBytes(8).toString('hex')}`);
82-
currentArgs = [
83-
...currentArgs,
84-
'--coverage',
85-
'--coveragePath',
86-
coverageDir,
87-
'--coverageFormats',
88-
'json',
89-
'--coverageFormats',
90-
'html',
91-
];
88+
// todo: browser runs currently don't support per-test coverage
89+
if (args.includes('--browser')) {
90+
coverageDir = path.join(
91+
tmpdir(),
92+
`vscode-test-coverage-${randomBytes(8).toString('hex')}`
93+
);
94+
currentArgs = [
95+
...currentArgs,
96+
'--coverage',
97+
'--coveragePath',
98+
coverageDir,
99+
'--coverageFormats',
100+
'json',
101+
];
102+
} else {
103+
currentArgs = [...currentArgs, '--per-test-coverage'];
104+
}
92105
}
93106

94107
return await scanTestOutput(
@@ -172,7 +185,13 @@ export async function activate(context: vscode.ExtensionContext) {
172185
true
173186
);
174187

175-
coverage.loadDetailedCoverage = coverageContext.loadDetailedCoverage;
188+
coverage.loadDetailedCoverage = async (_run, coverage) => {
189+
if (coverage instanceof V8CoverageFile) {
190+
return coverage.details;
191+
}
192+
193+
return [];
194+
};
176195

177196
for (const [name, arg] of browserArgs) {
178197
const cfg = ctrl.createRunProfile(

0 commit comments

Comments
 (0)