TypeScript Go (TypeScript 7)
repository·main·Indexed 12 days ago
https://github.com/microsoft/typescript-goA native implementation of the TypeScript language service providing high-performance IDE features such as completions, diagnostics, and go-to-definition. Includes the tsgo command as a drop-in replacement for tsc, a native preview extension for VS Code, and internal Go-based filesystem watching via fswatch.
What's inside TypeScript Go
- The TypeScript formatter is not exported publicly. It is an internal component used primarily by language service operations that insert or modify code. Consequently, all consumer access to formatting capabilities must be routed through the language server.
How Glob Patterns are Compiled
mainGlob patterns are transformed from a raw Spec into a Pattern via the
COMPILE_PATTERNprocess.- Normalization: The spec is resolved against a
basePathinto absolute path components. - Implicit Globbing: If the last component of the normalized path does not contain
.,*, or?, the algorithm treats it as an implicit glob by appending**and*to the components. - Component Classification:
**becomes aDoubleAsteriskcomponent.- Components without
*or?becomeLiteralcomponents. - Components with
*or?becomeWildcardcomponents, which are further parsed intoSegLiteral,SegStar, orSegQuestionsegments.
Note: If the last element of the normalized components is
**and the usage mode is notExclude, compilation will fail.- Normalization: The spec is resolved against a
Understand the Microsoft Support Policy
mainTypeScript support and servicing depend on how the project is being consumed:
- Standard Releases: TypeScript releases include new features and fixes (security and non-security). Critical issues may be addressed via servicing updates to the latest release.
- Microsoft Products: When bundled with a Microsoft product, support follows the Modern Support Policy.
- Visual Studio: For versions of Visual Studio that are in 'under-support' releases, servicing is limited to security fixes only.
- Community Support: Limited to GitHub issues, Stack Overflow, and Discord.
- Assisted Support: Professional support is available via the Microsoft assisted support team.
Understand `.min.js` default exclusion
mainThe glob matching algorithm includes a default exclusion rule for
.min.jsfiles to prevent them from being matched by default in certain scenarios.Rules for exclusion:
- The exclusion only applies when the pattern's usage mode is set to Files.
- It only applies to wildcard components.
- A file is excluded if:
- Its filename ends with the
.min.jssuffix (case-sensitivity depends on the pattern configuration). - OR the pattern itself explicitly mentions the
.min.jsor.min.suffix within its literal segments.
- Its filename ends with the
If the pattern is not in Files mode, or if the file/pattern does not meet the suffix criteria, the exclusion does not apply.
Understand the internal formatting lifecycle
mainThe internal formatting process follows this lifecycle:
- Initialization: Most APIs use
Format*methods to configure aFormatSpan, which defines the specific range of theSourceFileto be formatted. - Scanning: A scanner (with or without JSX support) identifies the highest-level node covering the span and recurses through its children.
- Indentation: As the scanner recurses,
processNodeis called on children to determine and pass down indentation levels. - Rule Application: The core logic resides in
processPair, which compares the current node with the previous node. This method mutates the formatting context and usescreateRulesMapto fetch a set of rules. - Rule Execution: Formatting decisions are driven by rules (defined in
rules.ts) that reference node pairs or token ranges to determine which actions to apply.
- Initialization: Most APIs use
Understand Glob Matching Algorithm Concepts
mainThe glob matching logic follows a formal specification to ensure consistent file-path matching. Key concepts include:
- Path: A normalized,
/-separated absolute file path (e.g.,/project/src/index.ts). - Path component: A single segment between
/delimiters. The root component is an empty string"". - Spec: The raw user-provided glob string (e.g.,
src/**/*.ts). - Pattern: The compiled version of a spec, containing a list of components, a usage mode, and a case-sensitivity flag.
- Usage Modes:
Files: Matches complete file paths.Directories: Matches directory prefixes for traversal pruning.Exclude: Matches paths to be excluded.
- Component Kinds:
Literal: No*or?characters.Wildcard: Contains*or?characters.DoubleAsterisk: The exact string**.
- Segment Kinds (within a Wildcard component):
SegLiteral: An exact literal substring.SegStar: Matches zero or more characters excluding/.SegQuestion: Matches exactly one character excluding/.
- Path: A normalized,
Select a specific filesystem watcher
mainWhile
fswatch.Default()automatically selects the best watcher for the current OS, you can explicitly request a specific backend. All watchers are available on every platform, but they may not be supported by the underlying kernel.To check if a watcher is supported at runtime, use
fswatch.Available(). If you attempt to use an unsupported watcher,WatchDirectorywill returnfswatch.ErrUnavailable.Supported watchers by OS:
- linux:
fanotify(default, kernel ≥ 5.13),inotify - darwin:
FSEvents(default),kqueue - windows:
ReadDirectoryChangesW - freebsd, openbsd, netbsd, dragonfly:
kqueue
// Example of using a specific watcher with options sub, err := fswatch.Inotify().WatchDirectory(dir, callback, fswatch.WithRecursive())- linux:
How TypeScript formatting works
mainTypeScript formatting requires two primary components: a
SourceFilerepresenting the code and a formatting context containing user settings (such astab sizeandnewline character).The output of the formatting process is a collection of
TextChangeobjects. EachTextChangeobject contains the new string content and the specific text it is intended to replace.Rules for Wildcard and Double Asterisk Matching
mainThe matching algorithm applies specific constraints during traversal and wildcard evaluation:
- Hidden Paths: If a component starts with
.(e.g.,.gitignore), it is considered a hidden path. If aDoubleAsteriskor aWildcard(starting with*or?) attempts to match a hidden path, the match will fail (unless inExcludemode). - Package Folders: Components matching
node_modules,bower_components, orjspm_packages(case-insensitive) are treated as package folders. If aDoubleAsteriskor aWildcardcomponent encounters a package folder, the match is rejected (unless inExcludemode). - Double Asterisk (
**): This component allows for matching across multiple directory levels. It attempts to skip segments to find a valid match for the subsequent pattern components.
- Hidden Paths: If a component starts with
Understand fswatch event behavior
mainWhen consuming events from
fswatch, be aware of the following behaviors:- Batching: Events arriving in quick succession are batched together before being delivered to the callback.
- Ordering: The order of events within a single batch is not guaranteed.
- Paths: All paths in events are absolute. Because backends report canonical paths, always resolve symlinks before subscribing using
filepath.EvalSymlinksto ensure consistency.
Algorithm Invariants and Constraints
mainWhen implementing or using the glob matching algorithm, be aware of these core invariants:
- Invalid Patterns: Any include or directory spec ending in
**will causeCOMPILE_PATTERNto returnfailure. - Pattern Exhaustion: If a pattern is exhausted but path components remain, exclude patterns return
trueand all other patterns returnfalse. - Complexity:
MATCH_SEGMENTSis guaranteed to be $O(n imes m)$, where $n$ is string length and $m$ is segment count. - Precedence: Excludes are always evaluated before includes.
- Wildcard Behavior:
- For include patterns,
**does not descend into hidden paths or package folders. - A wildcard component whose first segment is a star (
*) or question mark (?) will not match hidden path components. - For include patterns, wildcard components reject package folders, while literal components do not.
- For include patterns,
- Symlinks: Symlink cycles are detected via canonical paths and the directory is skipped.
- Invalid Patterns: Any include or directory spec ending in
Use fswatch to monitor filesystem changes
mainTo monitor a directory for changes, use
fswatch.Default().WatchDirectory(path, callback). The callback receives a slice offswatch.Eventobjects and an error. Each event contains aKindand an absolutePath.Note that the callback runs on a library goroutine and is serialized for each watch, meaning the same watch's callback will never run concurrently with itself. Because backends report canonical paths, you should resolve symlinks using
filepath.EvalSymlinksbefore subscribing to ensure the path matches your expectations.package main import ( "fmt" "log" "os" "os/signal" "github.com/microsoft/typescript-go/internal/fswatch" ) func main() { dir, _ := os.Getwd() sub, err := fswatch.Default().WatchDirectory(dir, func(events []fswatch.Event, err error) { if err != nil { log.Println("watch error:", err) return } for _, e := range events { fmt.Printf("%s %s\n", e.Kind, e.Path) } }) if err != nil { log.Fatal(err) } defer sub.Close() c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) <-c }