Skip to content
Draft
349 changes: 51 additions & 298 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,310 +1,34 @@
# Guide for Copilot
## Documentation MCP server

This document provides a concise guide for writing TypeScript fourslash tests and compiler tests, along with build instructions.
The repo is large and the project is complex.
This document contains information you'll need no matter what the task is, but we have a separate library of content that you'll need to consult depending on the issue.

## Build Instructions Summary
You have been given the `md-fragments` MCP server.
Before doing anything, query its `list-topics` endpoint and remember all the topics you saw.
Consult these topics often, as they contain important information relevant to the work.
MOST OPERATIONS (adding tests, running them, etc) HAVE RELEVANT DOCUMENTATION.

### Setup
1. Install Node.js (current or LTS)
2. Clone the repository: `git clone --depth=1 https://github.com/microsoft/TypeScript`
3. Install dependencies: `npm ci`
YOU MUST FOLLOW DIRECTIONS FROM THE "HOW TO FINISH A SESSION" TOPIC BEFORE FINISHING A PULL REQUEST.

### Common Build Tasks
```bash
npx hereby local # Build the compiler into built/local
npx hereby clean # Delete the built compiler
npx hereby tests # Build the test infrastructure
npx hereby runtests # Run all tests
npx hereby runtests-parallel # Run tests in parallel (recommended)
npx hereby runtests --runner=fourslash # Run only fourslash tests
npx hereby runtests --runner=compiler # Run only compiler tests
npx hereby runtests --tests=<testPath> # Run specific test
npx hereby baseline-accept # Accept new test baselines
npx hereby lint # Run eslint
npx hereby format # Run code formatting
```

## Fourslash Test Syntax Guide

Fourslash tests are interactive TypeScript language service tests. They validate IDE features like completions, quick info, navigation, and refactoring.

### Basic Structure
```typescript
/// <reference path='fourslash.ts'/>

////code goes here with /*markers*/

// Test assertions go here
```

### Key Syntax Elements

#### 1. Source Code Definition
Use `////` to define source code lines:
```typescript
////function foo(x: number) {
//// return x + 1;
////}
////let result = foo(/*marker*/42);
```

#### 2. Markers for Positioning
Use `/**/` for anonymous markers or `/*name*/` for named markers:
```typescript
////let x = /*1*/someValue;
////let y = /*cursor*/anotherValue;
```

#### 3. Multi-file Tests
Use `// @Filename:` to define multiple files:
```typescript
// @Filename: /a.ts
////export const value = 42;

// @Filename: /b.ts
////import { value } from './a';
////console.log(/*marker*/value);
```

#### 4. Ranges
Use `[|text|]` to define text ranges:
```typescript
////function test() {
//// [|return 42;|]
////}
```

### Common API Patterns

#### Navigation & Positioning
```typescript
goTo.marker("markerName"); // Navigate to marker
goTo.marker(); // Navigate to anonymous marker /**/
```

#### Verification (Prefer these over baselines)
```typescript
verify.currentLineContentIs("expected content");
verify.completions({ includes: "itemName" });
verify.completions({ excludes: "itemName" });
verify.quickInfoIs("expected info");
verify.codeFix({
description: "Fix description",
newFileContent: "expected content after fix"
});
```

#### Completions Testing
```typescript
verify.completions({
marker: "1",
includes: { name: "foo", source: "/a", hasAction: true },
isNewIdentifierLocation: true,
preferences: { includeCompletionsForModuleExports: true }
});
```

#### Code Fixes Testing
```typescript
verify.codeFix({
description: "Add missing property",
index: 0,
newFileContent: `class C {
property: string;
method() { this.property = "value"; }
}`
});
```

#### Formatting
```typescript
format.document();
verify.currentLineContentIs("formatted content");
```

### Simple Example
```typescript
/// <reference path='fourslash.ts'/>

////interface User {
//// name: string;
////}
////
////const user: User = {
//// /*completion*/
////};

verify.completions({
marker: "completion",
includes: { name: "name", sortText: "0" }
});
```

## Compiler Test Syntax Guide

Compiler tests validate TypeScript compilation behavior, type checking, and error reporting.

### Basic Structure
- Simple `.ts` files in `tests/cases/compiler/`
- Use comments to indicate expected behavior
- No special test harness - just TypeScript code

### Compiler Directives
Use `// @directive: value` for compiler options:
```typescript
// @strict: true
// @target: ES2015
// @lib: ES2015,DOM

let x: string = 42; // Error expected
```

### Common Directives
```typescript
// @strict: true/false
// @noImplicitAny: true/false
// @target: ES5/ES2015/ES2020/ESNext
// @module: commonjs/amd/es6/esnext
// @lib: ES5,DOM/ES2015/ES2020
// @declaration: true/false
// @skipLibCheck: true/false
```

### Multi-file Tests
```typescript
// @Filename: helper.ts
export function helper(x: number): string {
return x.toString();
}

// @Filename: main.ts
import { helper } from "./helper";
const result = helper(42);
```

### Error Expectations
Use comments to document expected behavior:
```typescript
abstract class Base {
abstract method(): void;
}

class Derived extends Base {
// Missing implementation - should error
}

new Base(); // Should error - cannot instantiate abstract class
```

### Type Testing Patterns
```typescript
// Test type inference
let inferred = [1, 2, 3]; // Should infer number[]

// Test type compatibility
type A = { x: number };
type B = { x: number; y: string };
let a: A = { x: 1 };
let b: B = { x: 1, y: "hello" };
a = b; // Should work - B is assignable to A
b = a; // Should error - A missing property y
```

### Simple Example
```typescript
// Test that optional properties work correctly
interface Config {
required: string;
optional?: number;
}

const config1: Config = { required: "test" }; // Should work
const config2: Config = { required: "test", optional: 42 }; // Should work
const config3: Config = { optional: 42 }; // Should error - missing required
```

## Test Writing Best Practices

### For Fourslash Tests
1. **Prefer validation over baselines** - Use `verify.currentLineContentIs()` instead of `verify.baseline*()`
2. **Use simple, focused examples** - Test one feature at a time
3. **Name markers clearly** - Use descriptive marker names like `/*completion*/`
4. **Test the simplest form first** - Start with basic cases before complex scenarios

### For Compiler Tests
1. **Use clear file names** - Name tests after the feature being tested
2. **Add explanatory comments** - Document expected behavior with comments
3. **Test error cases** - Include both valid and invalid code examples
4. **Keep tests focused** - One primary feature per test file

### General Guidelines
1. **Make tests deterministic** - Avoid random or environment-dependent behavior
2. **Use realistic examples** - Test scenarios developers actually encounter
3. **Start simple** - Begin with the most basic case of a feature
4. **Test edge cases** - Include boundary conditions and error scenarios

## Running Specific Tests

```bash
# Run a specific fourslash test
npx hereby runtests --tests=tests/cases/fourslash/completionForObjectProperty.ts

# Run a specific compiler test
npx hereby runtests --tests=tests/cases/compiler/abstractClassUnionInstantiation.ts

# Run tests matching a pattern
npx hereby runtests --tests=tests/cases/fourslash/completion*.ts
```

## Important Guidelines

### Keeping Things Tidy
## Information About This Repo

- Once you think you're done, run `npx hereby lint` and fix any issues
- Then always run `npx hereby format` as your last step
Facts you should know and remember:
* All tests can run and pass in this environment. There are no "unrelated" test failures!
* Test "failures" due to baseline changes are normal as a result of your changes, but they MUST BE ADDRESSED. Read the "Dealing with Baselines" topic to learn more.
* Maintainer comments in the issue should generally take priority over OP's comments
* Maintainers might give you hints on where to start. They are not always right, but a good place to start

### Test Locations
## Mandatory Workflow

- Only add testcases in `tests/cases/compiler` or `tests/cases/fourslash`
- Filenames in `tests/cases/compiler` must always end with `.ts`, not `.d.ts`
- Do not write direct unit tests as they are almost never the correct test format for our repo
When you clone this repo, ALL THE TESTS ARE PASSING. There are no "unrelated" test failures here; if a test is failing, it's because of your change, and you need to address that one way or another.

### Performance Expectations

- Running a set of tests may take up to 4 minutes
- A full test run may take up to 15 minutes

### Working with Issues

- Maintainer comments in the issue should generally take priority over OP's comments
- Maintainers might give you hints on where to start. They are not always right, but a good place to start

### Debugging Tips

printf debugging is going to be very useful as you are figuring things out.
To do this, use `console.log`, but you'll need to `ts-ignore` it.
Write something like this:
```ts,diff
function checkSomething(n: Node) {
doSomething(n);
+ // @ts-ignore DEBUG CODE ONLY, REMOVE ME WHEN DONE
+ console.log(`Got node with pos = ${n.pos}`);
doSomethingElse(n);
}
```
We have a lot of enums so you might want to print back their symbolic name, to do this, index back into the name of the enum
```ts
// @ts-ignore DEBUG CODE ONLY, REMOVE ME WHEN DONE
console.log(`Got node with kind = ${SyntaxKind[n.kind]}`);
```

## Recommended Workflow

When fixing bugs or implementing features, follow this workflow:
This repo uses test-driven development. When fixing bugs or implementing features, you must follow this workflow:

1. **Make a testcase that demonstrates the behavior**
- Run it (by itself) and review the baselines it generates to ensure it demonstrates the bug
- Add the test and its baselines in one commit
- You may need to debug in order to figure out how to write a testcase; this is normal
- DO NOT TRY TO FIX A BUG UNTIL YOU HAVE A TESTCASE THAT CORRECTLY DEMONSTRATES THE PROBLEM

2. **Fix the bug by changing code as appropriate**
- Put this fix in another commit
Expand All @@ -322,6 +46,35 @@ When fixing bugs or implementing features, follow this workflow:
- Some collateral baseline changes are normal, but review for correctness
- Put these diffs in another commit

6. **Always format and lint**
- Don't forget to run `npx hereby lint` and `npx hereby format` before you're done
- Double-check your line endings. Source files in this repo typically use CRLF line endings. Fix all line endings to be consistent before you wrap up
## Due Diligence

As part of your summary, you will need to provide an extensive root cause analysis of why the bug has occurred.
You should investigate the provided repro thoroughly, and provide "adjacent" testcases that *don't* demonstrate the bug to prove your theory of what the root cause of the bug is.

In particular, pay attention to which phase the bug occurs in. For example:
* If the bug is in the parser, you should be able to demonstrate that the syntax tree is wrong
* If the bug is in the checker, you should be able to explain why the logic is wrong with constrasting examples
* If the bug is in the emitter, you should be able to demonstrate that the syntax tree is correct, but that the emit logic is wrong and why

## Time Constraints

If you're running out of time, consult the "How to give up" documentation topic.

## Asking Questions

We want to make you smarter over time.
If you encounter a situation where you think a developer on this project would be able to provide a useful answer *and* it's not something offered by the Documentation MCP server, add a question to the file `.github/copilot-questions.md`
Explain what you searched for so that we can put the right search terms in the documentation library.

## Common Commands

You'll need to run these commands often. Always use `npx` to run `hereby` commands.

```bash
npx hereby local # Build the compiler into built/local
npx hereby runtests-parallel # Run all tests; this will take 10-15 minutes
npx hereby runtests -t <grep> # Run testcases matching a specific pattern
npx hereby baseline-accept # Accept new test baselines
npx hereby lint # Run lint. Always do this before submitting
npx hereby format # Run code formatting. Always do this before submitting
```
Loading