vendor tsgo
This commit is contained in:
@@ -1,54 +1,54 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
// Frontend TypeScript checker. Runs tsc in noEmit mode using
|
// Frontend TypeScript checker using TypeScript 7 (tsgo) - Microsoft's native Go
|
||||||
// tsconfig.json. Requires node on PATH; downloads the pinned TypeScript
|
// port of tsc. No npm, no Node: tsgo is built from the vendored source under
|
||||||
// release on first run (no npm).
|
// kjol/tools/tsgo and executed directly.
|
||||||
//
|
//
|
||||||
// go run ./cmd/typecheck
|
// go run kjol/cmd/typecheck
|
||||||
// go run ./cmd/typecheck -p tsconfig.json
|
// go run kjol/cmd/typecheck -p tsconfig.json
|
||||||
|
// go run kjol/cmd/typecheck -tsgo path/to/kjol/tools/tsgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
|
||||||
"compress/gzip"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const typescriptVersion = "5.8.3"
|
// tsgoVersion pins the vendored typescript-go source (kjol/tools/tsgo). Bump when
|
||||||
|
// the vendored copy is updated; it also keys the built-binary cache.
|
||||||
|
const tsgoVersion = "v0.0.0-20260709155237-487baf0cc74a" // TypeScript 7.1.0-dev
|
||||||
|
|
||||||
|
// goToolchain is the Go toolchain used to build tsgo. Its go.mod needs >= go 1.26;
|
||||||
|
// this exact patch is known-good. Go downloads it once if absent.
|
||||||
|
const goToolchain = "go1.26.5"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
tsconfig := flag.String("p", "tsconfig.json", "path to tsconfig.json")
|
tsconfig := flag.String("p", "tsconfig.json", "path to tsconfig.json")
|
||||||
|
tsgoDir := flag.String("tsgo", "kjol/tools/tsgo", "path to the vendored typescript-go source")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if err := runTypecheck(*tsconfig); err != nil {
|
if err := runTypecheck(*tsconfig, *tsgoDir); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Typecheck failed: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Typecheck failed: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTypecheck(tsconfig string) error {
|
func runTypecheck(tsconfig, tsgoDir string) error {
|
||||||
node, err := exec.LookPath("node")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("node not found on PATH (required to run tsc): %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tsc, err := ensureTypeScript()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(tsconfig); err != nil {
|
if _, err := os.Stat(tsconfig); err != nil {
|
||||||
return fmt.Errorf("tsconfig not found: %s", tsconfig)
|
return fmt.Errorf("tsconfig not found: %s", tsconfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Typechecking with TypeScript %s...\n", typescriptVersion)
|
tsgo, err := ensureTsgo(tsgoDir)
|
||||||
cmd := exec.Command(node, tsc, "--noEmit", "-p", tsconfig)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Typechecking with TypeScript 7 (tsgo %s)...\n", tsgoVersion)
|
||||||
|
cmd := exec.Command(tsgo, "--noEmit", "-p", tsconfig)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
@@ -59,92 +59,56 @@ func runTypecheck(tsconfig string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureTypeScript() (string, error) {
|
// ensureTsgo builds tsgo from the vendored source once (cached under tmp/tsgo) and
|
||||||
root, err := os.Getwd()
|
// returns the binary path.
|
||||||
|
func ensureTsgo(tsgoDir string) (string, error) {
|
||||||
|
exeName := "tsgo"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
exeName += ".exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
binPath := filepath.Join(cwd, "tmp", "tsgo", tsgoVersion, exeName)
|
||||||
cacheDir := filepath.Join(root, "tools", ".cache", "typescript", typescriptVersion)
|
if _, err := os.Stat(binPath); err == nil {
|
||||||
tscPath := filepath.Join(cacheDir, "package", "lib", "tsc.js")
|
return binPath, nil
|
||||||
if _, err := os.Stat(tscPath); err == nil {
|
|
||||||
return tscPath, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Downloading TypeScript %s...\n", typescriptVersion)
|
absTsgo, err := filepath.Abs(tsgoDir)
|
||||||
if err := downloadTypeScript(cacheDir); err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(absTsgo, "go.mod")); err != nil {
|
||||||
if _, err := os.Stat(tscPath); err != nil {
|
return "", fmt.Errorf("vendored tsgo source not found at %s (pass -tsgo or check kjol/tools/tsgo)", absTsgo)
|
||||||
return "", fmt.Errorf("tsc not found after download: %s", tscPath)
|
|
||||||
}
|
|
||||||
return tscPath, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadTypeScript(destDir string) error {
|
if err := os.MkdirAll(filepath.Dir(binPath), 0o755); err != nil {
|
||||||
url := fmt.Sprintf("https://registry.npmjs.org/typescript/-/typescript-%s.tgz", typescriptVersion)
|
return "", err
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("download typescript: %w", err)
|
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
fmt.Println("Building tsgo from vendored source (first run; cached afterwards)...")
|
||||||
|
build := exec.Command("go", "build", "-C", absTsgo, "-mod=vendor", "-o", binPath, "./cmd/tsgo")
|
||||||
if resp.StatusCode != http.StatusOK {
|
build.Env = buildEnv()
|
||||||
return fmt.Errorf("download typescript: HTTP %s", resp.Status)
|
build.Stdout = os.Stdout
|
||||||
|
build.Stderr = os.Stderr
|
||||||
|
if err := build.Run(); err != nil {
|
||||||
|
return "", fmt.Errorf("building tsgo: %w", err)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(binPath); err != nil {
|
||||||
|
return "", fmt.Errorf("tsgo not found after build: %s", binPath)
|
||||||
|
}
|
||||||
|
return binPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(destDir, 0o755); err != nil {
|
// buildEnv builds tsgo standalone: outside any go.work, with a pinned toolchain.
|
||||||
return err
|
func buildEnv() []string {
|
||||||
}
|
var env []string
|
||||||
return extractTGZ(resp.Body, destDir)
|
for _, e := range os.Environ() {
|
||||||
}
|
if strings.HasPrefix(e, "GOWORK=") || strings.HasPrefix(e, "GOTOOLCHAIN=") {
|
||||||
|
continue
|
||||||
func extractTGZ(r io.Reader, destDir string) error {
|
|
||||||
gz, err := gzip.NewReader(r)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("read typescript archive: %w", err)
|
|
||||||
}
|
|
||||||
defer gz.Close()
|
|
||||||
|
|
||||||
tr := tar.NewReader(gz)
|
|
||||||
cleanDest := filepath.Clean(destDir)
|
|
||||||
|
|
||||||
for {
|
|
||||||
hdr, err := tr.Next()
|
|
||||||
if err == io.EOF {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("read typescript archive: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
target := filepath.Join(destDir, filepath.FromSlash(hdr.Name))
|
|
||||||
cleanTarget := filepath.Clean(target)
|
|
||||||
if cleanTarget != cleanDest && !strings.HasPrefix(cleanTarget, cleanDest+string(os.PathSeparator)) {
|
|
||||||
return fmt.Errorf("invalid archive path: %s", hdr.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch hdr.Typeflag {
|
|
||||||
case tar.TypeDir:
|
|
||||||
if err := os.MkdirAll(target, 0o755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case tar.TypeReg:
|
|
||||||
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(hdr.Mode)&0o777|0o600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := io.Copy(f, tr); err != nil {
|
|
||||||
f.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := f.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
env = append(env, e)
|
||||||
}
|
}
|
||||||
|
return append(env, "GOWORK=off", "GOTOOLCHAIN="+goToolchain)
|
||||||
}
|
}
|
||||||
55
tools/tsgo/LICENSE
Normal file
55
tools/tsgo/LICENSE
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
Apache License
|
||||||
|
|
||||||
|
Version 2.0, January 2004
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||||
|
|
||||||
|
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||||
|
|
||||||
|
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
436
tools/tsgo/NOTICE.txt
Normal file
436
tools/tsgo/NOTICE.txt
Normal file
File diff suppressed because one or more lines are too long
61
tools/tsgo/cmd/tsgo/api.go
Normal file
61
tools/tsgo/cmd/tsgo/api.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/api"
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runAPI(args []string) int {
|
||||||
|
flag := flag.NewFlagSet("api", flag.ContinueOnError)
|
||||||
|
cwd := flag.String("cwd", core.Must(os.Getwd()), "current working directory")
|
||||||
|
pipePath := flag.String("pipe", "", "use named pipe or Unix domain socket for communication instead of stdio")
|
||||||
|
callbacks := flag.String("callbacks", "", "comma-separated list of FS callbacks to enable (readFile,fileExists,directoryExists,getAccessibleEntries,realpath)")
|
||||||
|
async := flag.Bool("async", false, "use JSON-RPC protocol instead of MessagePack (for async API)")
|
||||||
|
timing := flag.Bool("timing", false, "collect per-request server processing time, folded into the client's timing snapshot")
|
||||||
|
if err := flag.Parse(args); err != nil {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultLibraryPath := bundled.LibPath()
|
||||||
|
|
||||||
|
// Parse callbacks list
|
||||||
|
var callbacksList []string
|
||||||
|
if *callbacks != "" {
|
||||||
|
callbacksList = strings.Split(*callbacks, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
options := &api.StdioServerOptions{
|
||||||
|
Err: os.Stderr,
|
||||||
|
Cwd: *cwd,
|
||||||
|
DefaultLibraryPath: defaultLibraryPath,
|
||||||
|
Callbacks: callbacksList,
|
||||||
|
Async: *async,
|
||||||
|
CollectTiming: *timing,
|
||||||
|
}
|
||||||
|
if *pipePath != "" {
|
||||||
|
options.PipePath = *pipePath
|
||||||
|
} else {
|
||||||
|
options.In = os.Stdin
|
||||||
|
options.Out = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
s := api.NewStdioServer(options)
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
if err := s.Run(ctx); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
22
tools/tsgo/cmd/tsgo/enablevtprocessing_windows.go
Normal file
22
tools/tsgo/cmd/tsgo/enablevtprocessing_windows.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
h, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
|
||||||
|
if err != nil || h == windows.InvalidHandle {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileType, err := windows.GetFileType(h)
|
||||||
|
if err != nil || fileType == windows.FILE_TYPE_CHAR {
|
||||||
|
var mode uint32
|
||||||
|
if err := windows.GetConsoleMode(h, &mode); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
|
||||||
|
_ = windows.SetConsoleMode(h, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
tools/tsgo/cmd/tsgo/isprocessalive_other.go
Normal file
9
tools/tsgo/cmd/tsgo/isprocessalive_other.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build !unix && !windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
const processAliveSupported = false
|
||||||
|
|
||||||
|
func isProcessAlive(pid int) bool {
|
||||||
|
panic("isProcessAlive is not supported on this platform")
|
||||||
|
}
|
||||||
25
tools/tsgo/cmd/tsgo/isprocessalive_unix.go
Normal file
25
tools/tsgo/cmd/tsgo/isprocessalive_unix.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//go:build unix
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const processAliveSupported = true
|
||||||
|
|
||||||
|
// isProcessAlive checks if a process with the given PID is still running.
|
||||||
|
// On Unix, FindProcess always succeeds, so we send signal 0 to probe the
|
||||||
|
// process. If the signal returns nil or EPERM, the process exists (EPERM
|
||||||
|
// means it exists but we lack permission to signal it). ESRCH or any
|
||||||
|
// other error indicates the process is gone.
|
||||||
|
func isProcessAlive(pid int) bool {
|
||||||
|
proc, err := os.FindProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = proc.Signal(syscall.Signal(0))
|
||||||
|
return err == nil || errors.Is(err, syscall.EPERM)
|
||||||
|
}
|
||||||
26
tools/tsgo/cmd/tsgo/isprocessalive_windows.go
Normal file
26
tools/tsgo/cmd/tsgo/isprocessalive_windows.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const processAliveSupported = true
|
||||||
|
|
||||||
|
// isProcessAlive checks if a process with the given PID is still running.
|
||||||
|
// On Windows, we open the process with SYNCHRONIZE access and use
|
||||||
|
// WaitForSingleObject with a zero timeout. If the wait times out, the
|
||||||
|
// process is still running. If the object is signaled, it has exited.
|
||||||
|
func isProcessAlive(pid int) bool {
|
||||||
|
const SYNCHRONIZE = 0x00100000
|
||||||
|
handle, err := syscall.OpenProcess(SYNCHRONIZE, false, uint32(pid))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer func() { _ = syscall.CloseHandle(handle) }()
|
||||||
|
ret, err := syscall.WaitForSingleObject(handle, 0)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const WAIT_TIMEOUT = 258
|
||||||
|
return ret == WAIT_TIMEOUT
|
||||||
|
}
|
||||||
108
tools/tsgo/cmd/tsgo/lsp.go
Normal file
108
tools/tsgo/cmd/tsgo/lsp.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/lsp"
|
||||||
|
"github.com/microsoft/typescript-go/internal/pprof"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runLSP(args []string) int {
|
||||||
|
flag := flag.NewFlagSet("lsp", flag.ContinueOnError)
|
||||||
|
stdio := flag.Bool("stdio", false, "use stdio for communication")
|
||||||
|
pprofDir := flag.String("pprofDir", "", "Generate pprof CPU/memory profiles to the given directory.")
|
||||||
|
pipe := flag.String("pipe", "", "use named pipe for communication")
|
||||||
|
_ = pipe
|
||||||
|
socket := flag.String("socket", "", "use socket for communication")
|
||||||
|
_ = socket
|
||||||
|
if err := flag.Parse(args); err != nil {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if !*stdio {
|
||||||
|
fmt.Fprintln(os.Stderr, "only stdio is supported")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if *pprofDir != "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "pprof profiles will be written to: %v\n", *pprofDir)
|
||||||
|
profileSession := pprof.BeginProfiling(*pprofDir, os.Stderr)
|
||||||
|
defer profileSession.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fs := bundled.WrapFS(osvfs.FS())
|
||||||
|
defaultLibraryPath := bundled.LibPath()
|
||||||
|
typingsLocation := osvfs.GetGlobalTypingsCacheLocation()
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
s := lsp.NewServer(&lsp.ServerOptions{
|
||||||
|
In: lsp.ToReader(os.Stdin),
|
||||||
|
Out: lsp.ToWriter(os.Stdout),
|
||||||
|
Err: os.Stderr,
|
||||||
|
Cwd: core.Must(os.Getwd()),
|
||||||
|
FS: fs,
|
||||||
|
DefaultLibraryPath: defaultLibraryPath,
|
||||||
|
TypingsLocation: typingsLocation,
|
||||||
|
NpmInstall: func(cwd string, args []string) ([]byte, error) {
|
||||||
|
cmd := exec.Command("npm", args...)
|
||||||
|
cmd.Dir = cwd
|
||||||
|
return cmd.Output()
|
||||||
|
},
|
||||||
|
ProgressDelay: 250 * time.Millisecond,
|
||||||
|
SetParentProcessID: newParentProcessWatchdog(ctx, stop),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := s.Run(ctx); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// newParentProcessWatchdog returns a SetParentProcessID callback if the platform
|
||||||
|
// supports process-alive checking, or nil otherwise.
|
||||||
|
func newParentProcessWatchdog(ctx context.Context, stop context.CancelFunc) func(int) {
|
||||||
|
if !processAliveSupported {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return func(parentPID int) {
|
||||||
|
startParentProcessWatchdog(ctx, stop, parentPID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// startParentProcessWatchdog starts a goroutine that monitors the parent process
|
||||||
|
// and cancels the context if the parent dies. This prevents orphaned language
|
||||||
|
// server processes when the editor crashes or is killed.
|
||||||
|
func startParentProcessWatchdog(ctx context.Context, stop context.CancelFunc, parentPID int) {
|
||||||
|
if parentPID <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
if !isProcessAlive(parentPID) {
|
||||||
|
fmt.Fprintf(os.Stderr, "Parent process %d has exited, shutting down.\n", parentPID)
|
||||||
|
stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
32
tools/tsgo/cmd/tsgo/main.go
Normal file
32
tools/tsgo/cmd/tsgo/main.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/execute"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
os.Exit(runMain())
|
||||||
|
}
|
||||||
|
|
||||||
|
func runMain() int {
|
||||||
|
core.ApplyDebugStackLimit()
|
||||||
|
args := os.Args[1:]
|
||||||
|
if len(args) > 0 {
|
||||||
|
switch args[0] {
|
||||||
|
case "--lsp":
|
||||||
|
return runLSP(args[1:])
|
||||||
|
case "--api":
|
||||||
|
return runAPI(args[1:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
result := execute.CommandLine(ctx, newSystem(), args, nil)
|
||||||
|
return int(result.Status)
|
||||||
|
}
|
||||||
76
tools/tsgo/cmd/tsgo/sys.go
Normal file
76
tools/tsgo/cmd/tsgo/sys.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/execute/tsc"
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
type osSys struct {
|
||||||
|
writer io.Writer
|
||||||
|
fs vfs.FS
|
||||||
|
defaultLibraryPath string
|
||||||
|
cwd string
|
||||||
|
start time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) SinceStart() time.Duration {
|
||||||
|
return time.Since(s.start)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) Now() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) FS() vfs.FS {
|
||||||
|
return s.fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) DefaultLibraryPath() string {
|
||||||
|
return s.defaultLibraryPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) GetCurrentDirectory() string {
|
||||||
|
return s.cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) Writer() io.Writer {
|
||||||
|
return s.writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) WriteOutputIsTTY() bool {
|
||||||
|
return term.IsTerminal(int(os.Stdout.Fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) GetWidthOfTerminal() int {
|
||||||
|
width, _, _ := term.GetSize(int(os.Stdout.Fd()))
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *osSys) GetEnvironmentVariable(name string) string {
|
||||||
|
return os.Getenv(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSystem() *osSys {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error getting current directory: %v\n", err)
|
||||||
|
os.Exit(int(tsc.ExitStatusInvalidProject_OutputsSkipped))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &osSys{
|
||||||
|
cwd: tspath.NormalizePath(cwd),
|
||||||
|
fs: bundled.WrapFS(osvfs.FS()),
|
||||||
|
defaultLibraryPath: bundled.LibPath(),
|
||||||
|
writer: os.Stdout,
|
||||||
|
start: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
38
tools/tsgo/go.mod
Normal file
38
tools/tsgo/go.mod
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
module github.com/microsoft/typescript-go
|
||||||
|
|
||||||
|
go 1.26
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Microsoft/go-winio v0.6.2
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20260623181947-01eb4420fa68
|
||||||
|
github.com/google/go-cmp v0.7.0
|
||||||
|
github.com/mackerelio/go-osstat v0.2.7
|
||||||
|
github.com/peter-evans/patience v0.3.0
|
||||||
|
github.com/zeebo/xxh3 v1.1.0
|
||||||
|
golang.org/x/sync v0.21.0
|
||||||
|
golang.org/x/sys v0.46.0
|
||||||
|
golang.org/x/term v0.44.0
|
||||||
|
golang.org/x/text v0.38.0
|
||||||
|
gotest.tools/v3 v3.5.2
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
|
github.com/matryer/moq v0.7.1 // indirect
|
||||||
|
golang.org/x/mod v0.37.0 // indirect
|
||||||
|
golang.org/x/tools v0.47.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
tool (
|
||||||
|
github.com/matryer/moq
|
||||||
|
golang.org/x/tools/cmd/stringer
|
||||||
|
)
|
||||||
|
|
||||||
|
ignore (
|
||||||
|
./_extension
|
||||||
|
./_packages
|
||||||
|
./_submodules
|
||||||
|
./built
|
||||||
|
./coverage
|
||||||
|
node_modules
|
||||||
|
)
|
||||||
34
tools/tsgo/go.sum
Normal file
34
tools/tsgo/go.sum
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20260623181947-01eb4420fa68 h1:KZaTBSyshWX3MP5jukJcNSuXDQTO+rNpt0J564dX/eg=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20260623181947-01eb4420fa68/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
|
github.com/mackerelio/go-osstat v0.2.7 h1:TCavZi10wF49bT6iQZ9eT2keGZQpC69MTDfdJej5e94=
|
||||||
|
github.com/mackerelio/go-osstat v0.2.7/go.mod h1:dwpYh5pIPmvk+IEwBKNIWRFMB92mrC08CmXOhDC7nQk=
|
||||||
|
github.com/matryer/moq v0.7.1 h1:/QaXqMAdOrLqlshW2z7SMS21jDi7aVrbW0wJrR+hhJk=
|
||||||
|
github.com/matryer/moq v0.7.1/go.mod h1:IabIiFkaKCyHxej25INgFR+fnOxSZFMv2LYrU+ioyDs=
|
||||||
|
github.com/peter-evans/patience v0.3.0 h1:rX0JdJeepqdQl1Sk9c9uvorjYYzL2TfgLX1adqYm9cA=
|
||||||
|
github.com/peter-evans/patience v0.3.0/go.mod h1:Kmxu5sY1NmBLFSStvXjX1wS9mIv7wMcP/ubucyMOAu0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||||
|
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||||
|
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
||||||
|
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||||
|
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||||
|
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||||
|
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||||
|
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
|
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||||
|
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||||
|
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||||
|
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||||
|
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||||
|
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
|
||||||
|
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
|
||||||
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
226
tools/tsgo/internal/api/callbackfs.go
Normal file
226
tools/tsgo/internal/api/callbackfs.go
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// callbackFS wraps a base filesystem and delegates certain operations
|
||||||
|
// to the client via RPC callbacks. This allows the API client to provide
|
||||||
|
// a virtual filesystem (e.g., in-memory files for testing).
|
||||||
|
//
|
||||||
|
// The callbacks to enable are specified at construction time via the
|
||||||
|
// --callbacks CLI flag. The connection is set via SetConnection after
|
||||||
|
// the transport connection is established.
|
||||||
|
type callbackFS struct {
|
||||||
|
base vfs.FS
|
||||||
|
enabledCallbacks map[string]bool
|
||||||
|
|
||||||
|
// conn and ctx are set after connection is established
|
||||||
|
conn Conn
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback names that can be enabled
|
||||||
|
const (
|
||||||
|
callbackReadFile = "readFile"
|
||||||
|
callbackFileExists = "fileExists"
|
||||||
|
callbackDirectoryExists = "directoryExists"
|
||||||
|
callbackGetAccessibleEntries = "getAccessibleEntries"
|
||||||
|
callbackRealpath = "realpath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isCallbackName(name string) bool {
|
||||||
|
switch name {
|
||||||
|
case callbackReadFile,
|
||||||
|
callbackFileExists,
|
||||||
|
callbackDirectoryExists,
|
||||||
|
callbackGetAccessibleEntries,
|
||||||
|
callbackRealpath:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCallbackFS creates a new callbackFS wrapping the given base filesystem.
|
||||||
|
// The callbacks slice specifies which filesystem operations should be delegated
|
||||||
|
// to the client (e.g., "readFile", "fileExists").
|
||||||
|
func newCallbackFS(base vfs.FS, callbacks []string) *callbackFS {
|
||||||
|
enabled := make(map[string]bool, len(callbacks))
|
||||||
|
for _, cb := range callbacks {
|
||||||
|
if !isCallbackName(cb) {
|
||||||
|
panic("unknown callback name: " + cb)
|
||||||
|
}
|
||||||
|
enabled[cb] = true
|
||||||
|
}
|
||||||
|
return &callbackFS{
|
||||||
|
base: base,
|
||||||
|
enabledCallbacks: enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConnection sets the RPC connection for callbacks.
|
||||||
|
// This must be called after the transport connection is established
|
||||||
|
// but before any filesystem operations that need callbacks.
|
||||||
|
func (fs *callbackFS) SetConnection(ctx context.Context, conn Conn) {
|
||||||
|
fs.ctx = ctx
|
||||||
|
fs.conn = conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// isEnabled returns true if the named callback is enabled.
|
||||||
|
func (fs *callbackFS) isEnabled(name string) bool {
|
||||||
|
return fs.enabledCallbacks[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// call invokes a callback on the client and returns the result.
|
||||||
|
func (fs *callbackFS) call(name string, arg any) ([]byte, error) {
|
||||||
|
if fs.conn == nil {
|
||||||
|
return nil, fmt.Errorf("CallbackFS: %s called before connection set", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := fs.conn.Call(fs.ctx, name, arg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseCaseSensitiveFileNames implements vfs.FS.
|
||||||
|
func (fs *callbackFS) UseCaseSensitiveFileNames() bool {
|
||||||
|
return fs.base.UseCaseSensitiveFileNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFile implements vfs.FS.
|
||||||
|
//
|
||||||
|
// The readFile callback uses a wrapped response format to distinguish three states:
|
||||||
|
// - undefined (fall back to real FS): null or empty on wire
|
||||||
|
// - null (not found, no fallback): {"content": null}
|
||||||
|
// - string content: {"content": "..."}
|
||||||
|
func (fs *callbackFS) ReadFile(path string) (contents string, ok bool) {
|
||||||
|
if fs.isEnabled(callbackReadFile) {
|
||||||
|
result, err := fs.call(callbackReadFile, path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if len(result) > 0 && string(result) != "null" {
|
||||||
|
var wrapper struct {
|
||||||
|
Content *string `json:"content"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(result, &wrapper); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if wrapper.Content == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return *wrapper.Content, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fs.base.ReadFile(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileExists implements vfs.FS.
|
||||||
|
func (fs *callbackFS) FileExists(path string) bool {
|
||||||
|
if fs.isEnabled(callbackFileExists) {
|
||||||
|
result, err := fs.call(callbackFileExists, path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if len(result) > 0 && string(result) != "null" {
|
||||||
|
return string(result) == "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fs.base.FileExists(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectoryExists implements vfs.FS.
|
||||||
|
func (fs *callbackFS) DirectoryExists(path string) bool {
|
||||||
|
if fs.isEnabled(callbackDirectoryExists) {
|
||||||
|
result, err := fs.call(callbackDirectoryExists, path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if len(result) > 0 && string(result) != "null" {
|
||||||
|
return string(result) == "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fs.base.DirectoryExists(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccessibleEntries implements vfs.FS.
|
||||||
|
func (fs *callbackFS) GetAccessibleEntries(path string) vfs.Entries {
|
||||||
|
if fs.isEnabled(callbackGetAccessibleEntries) {
|
||||||
|
result, err := fs.call(callbackGetAccessibleEntries, path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if len(result) > 0 {
|
||||||
|
var rawEntries *struct {
|
||||||
|
Files []string `json:"files"`
|
||||||
|
Directories []string `json:"directories"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(result, &rawEntries); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if rawEntries != nil {
|
||||||
|
return vfs.Entries{
|
||||||
|
Files: rawEntries.Files,
|
||||||
|
Directories: rawEntries.Directories,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fs.base.GetAccessibleEntries(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realpath implements vfs.FS.
|
||||||
|
func (fs *callbackFS) Realpath(path string) string {
|
||||||
|
if fs.isEnabled(callbackRealpath) {
|
||||||
|
result, err := fs.call(callbackRealpath, path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if len(result) > 0 && string(result) != "null" {
|
||||||
|
var realpath string
|
||||||
|
if err := json.Unmarshal(result, &realpath); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return realpath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fs.base.Realpath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteFile implements vfs.FS - always delegates to base (no callback support).
|
||||||
|
func (fs *callbackFS) WriteFile(path string, data string) error {
|
||||||
|
return fs.base.WriteFile(path, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendFile implements vfs.FS - always delegates to base (no callback support).
|
||||||
|
func (fs *callbackFS) AppendFile(path string, data string) error {
|
||||||
|
return fs.base.AppendFile(path, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove implements vfs.FS - always delegates to base (no callback support).
|
||||||
|
func (fs *callbackFS) Remove(path string) error {
|
||||||
|
return fs.base.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chtimes implements vfs.FS - always delegates to base (no callback support).
|
||||||
|
func (fs *callbackFS) Chtimes(path string, aTime time.Time, mTime time.Time) error {
|
||||||
|
return fs.base.Chtimes(path, aTime, mTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat implements vfs.FS - always delegates to base (no callback support).
|
||||||
|
func (fs *callbackFS) Stat(path string) vfs.FileInfo {
|
||||||
|
return fs.base.Stat(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkDir implements vfs.FS - always delegates to base (no callback support).
|
||||||
|
func (fs *callbackFS) WalkDir(root string, walkFn vfs.WalkDirFunc) error {
|
||||||
|
return fs.base.WalkDir(root, walkFn)
|
||||||
|
}
|
||||||
46
tools/tsgo/internal/api/conn.go
Normal file
46
tools/tsgo/internal/api/conn.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrConnClosed = errors.New("api: connection closed")
|
||||||
|
ErrRequestTimeout = errors.New("api: request timeout")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler processes incoming API requests and notifications.
|
||||||
|
type Handler interface {
|
||||||
|
// HandleRequest handles an incoming request and returns a result or error.
|
||||||
|
HandleRequest(ctx context.Context, method string, params json.Value) (any, error)
|
||||||
|
// HandleNotification handles an incoming notification.
|
||||||
|
HandleNotification(ctx context.Context, method string, params json.Value) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conn represents a bidirectional connection for API communication.
|
||||||
|
type Conn interface {
|
||||||
|
// Run starts processing messages on the connection.
|
||||||
|
// It blocks until the context is cancelled or an error occurs.
|
||||||
|
Run(ctx context.Context) error
|
||||||
|
|
||||||
|
// Call sends a request to the client and waits for a response.
|
||||||
|
Call(ctx context.Context, method string, params any) (json.Value, error)
|
||||||
|
|
||||||
|
// Notify sends a notification to the client (no response expected).
|
||||||
|
Notify(ctx context.Context, method string, params any) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalParams is a helper to unmarshal params into a typed struct.
|
||||||
|
func UnmarshalParams[T any](params json.Value) (*T, error) {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var v T
|
||||||
|
if err := json.Unmarshal(params, &v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &v, nil
|
||||||
|
}
|
||||||
231
tools/tsgo/internal/api/conn_async.go
Normal file
231
tools/tsgo/internal/api/conn_async.go
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
"github.com/microsoft/typescript-go/internal/jsonrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AsyncConn manages bidirectional JSON-RPC communication with async request handling.
|
||||||
|
// Each incoming request is handled in its own goroutine, allowing concurrent processing.
|
||||||
|
// This is the standard implementation for LSP-style JSON-RPC protocols.
|
||||||
|
type AsyncConn struct {
|
||||||
|
rwc io.ReadWriteCloser
|
||||||
|
protocol Protocol
|
||||||
|
handler Handler
|
||||||
|
|
||||||
|
// timing, when non-nil, accumulates the wall-clock time spent handling each
|
||||||
|
// request. Clients retrieve the collected data via a getServerTiming request.
|
||||||
|
timing *timingCollector
|
||||||
|
|
||||||
|
// For server→client requests
|
||||||
|
seq atomic.Int64
|
||||||
|
pending map[jsonrpc.ID]chan *Message
|
||||||
|
pendingMu sync.Mutex
|
||||||
|
writeMu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAsyncConn creates a new async connection with the given transport and handler.
|
||||||
|
// It uses JSONRPCProtocol (LSP-style Content-Length framing) by default.
|
||||||
|
func NewAsyncConn(rwc io.ReadWriteCloser, handler Handler) *AsyncConn {
|
||||||
|
return NewAsyncConnWithProtocol(rwc, NewJSONRPCProtocol(rwc), handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAsyncConnWithProtocol creates a new async connection with a custom protocol.
|
||||||
|
func NewAsyncConnWithProtocol(rwc io.ReadWriteCloser, protocol Protocol, handler Handler) *AsyncConn {
|
||||||
|
return &AsyncConn{
|
||||||
|
rwc: rwc,
|
||||||
|
protocol: protocol,
|
||||||
|
handler: handler,
|
||||||
|
pending: make(map[jsonrpc.ID]chan *Message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCollectTiming enables or disables per-request server processing-time
|
||||||
|
// measurement. When enabled, the connection accumulates timing that clients can
|
||||||
|
// retrieve via a getServerTiming request.
|
||||||
|
func (c *AsyncConn) SetCollectTiming(enabled bool) {
|
||||||
|
if enabled {
|
||||||
|
c.timing = newTimingCollector()
|
||||||
|
} else {
|
||||||
|
c.timing = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts processing messages on the connection.
|
||||||
|
// It blocks until the context is cancelled or an error occurs.
|
||||||
|
func (c *AsyncConn) Run(ctx context.Context) error {
|
||||||
|
for {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := c.protocol.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.IsResponse() {
|
||||||
|
c.handleResponse(msg)
|
||||||
|
} else if msg.IsRequest() {
|
||||||
|
go c.handleRequest(ctx, msg)
|
||||||
|
} else if msg.IsNotification() {
|
||||||
|
go c.handleNotification(ctx, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleResponse matches a response to a pending request.
|
||||||
|
func (c *AsyncConn) handleResponse(msg *Message) {
|
||||||
|
c.pendingMu.Lock()
|
||||||
|
ch, ok := c.pending[*msg.ID]
|
||||||
|
if ok {
|
||||||
|
delete(c.pending, *msg.ID)
|
||||||
|
}
|
||||||
|
c.pendingMu.Unlock()
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
ch <- msg
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleRequest processes an incoming request.
|
||||||
|
func (c *AsyncConn) handleRequest(ctx context.Context, msg *Message) {
|
||||||
|
// Intercept the meta-requests for collected server timing before dispatching
|
||||||
|
// to the handler, so they are answered directly and not themselves recorded.
|
||||||
|
switch msg.Method {
|
||||||
|
case string(MethodGetServerTiming):
|
||||||
|
c.writeMu.Lock()
|
||||||
|
writeErr := c.protocol.WriteResponse(msg.ID, serverTimingSnapshot(c.timing))
|
||||||
|
c.writeMu.Unlock()
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write server timing response: %v", writeErr))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case string(MethodResetServerTiming):
|
||||||
|
if c.timing != nil {
|
||||||
|
c.timing.reset()
|
||||||
|
}
|
||||||
|
c.writeMu.Lock()
|
||||||
|
writeErr := c.protocol.WriteResponse(msg.ID, nil)
|
||||||
|
c.writeMu.Unlock()
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write reset server timing response: %v", writeErr))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var result any
|
||||||
|
var err error
|
||||||
|
|
||||||
|
start := time.Time{}
|
||||||
|
if c.timing != nil {
|
||||||
|
start = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recover from panics and convert to error response with stack trace
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
stack := string(debug.Stack())
|
||||||
|
err = fmt.Errorf("panic: %v\n%s", r, stack)
|
||||||
|
|
||||||
|
c.writeMu.Lock()
|
||||||
|
writeErr := c.protocol.WriteError(msg.ID, &jsonrpc.ResponseError{
|
||||||
|
Code: jsonrpc.CodeInternalError,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
c.writeMu.Unlock()
|
||||||
|
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write panic error response: %v (original panic: %v)", writeErr, r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
result, err = c.handler.HandleRequest(ctx, msg.Method, msg.Params)
|
||||||
|
|
||||||
|
if c.timing != nil {
|
||||||
|
c.timing.record(msg.Method, time.Since(start))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.writeMu.Lock()
|
||||||
|
defer c.writeMu.Unlock()
|
||||||
|
|
||||||
|
var writeErr error
|
||||||
|
if err != nil {
|
||||||
|
writeErr = c.protocol.WriteError(msg.ID, &jsonrpc.ResponseError{
|
||||||
|
Code: jsonrpc.CodeInternalError,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
writeErr = c.protocol.WriteResponse(msg.ID, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write response: %v", writeErr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleNotification processes an incoming notification.
|
||||||
|
func (c *AsyncConn) handleNotification(ctx context.Context, msg *Message) {
|
||||||
|
_ = c.handler.HandleNotification(ctx, msg.Method, msg.Params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call sends a request to the client and waits for a response.
|
||||||
|
func (c *AsyncConn) Call(ctx context.Context, method string, params any) (json.Value, error) {
|
||||||
|
// Create unique request ID
|
||||||
|
id := jsonrpc.NewIDString(fmt.Sprintf("api%d", c.seq.Add(1)))
|
||||||
|
|
||||||
|
// Register response channel BEFORE sending request to avoid race
|
||||||
|
responseChan := make(chan *Message, 1)
|
||||||
|
c.pendingMu.Lock()
|
||||||
|
c.pending[*id] = responseChan
|
||||||
|
c.pendingMu.Unlock()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
c.pendingMu.Lock()
|
||||||
|
defer c.pendingMu.Unlock()
|
||||||
|
if ch, ok := c.pending[*id]; ok {
|
||||||
|
close(ch)
|
||||||
|
delete(c.pending, *id)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
c.writeMu.Lock()
|
||||||
|
err := c.protocol.WriteRequest(id, method, params)
|
||||||
|
c.writeMu.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case resp := <-responseChan:
|
||||||
|
if resp.Error != nil {
|
||||||
|
return nil, fmt.Errorf("api: remote error [%d]: %s", resp.Error.Code, resp.Error.Message)
|
||||||
|
}
|
||||||
|
return resp.Result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify sends a notification to the client (no response expected).
|
||||||
|
func (c *AsyncConn) Notify(ctx context.Context, method string, params any) error {
|
||||||
|
c.writeMu.Lock()
|
||||||
|
defer c.writeMu.Unlock()
|
||||||
|
return c.protocol.WriteNotification(method, params)
|
||||||
|
}
|
||||||
208
tools/tsgo/internal/api/conn_sync.go
Normal file
208
tools/tsgo/internal/api/conn_sync.go
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
"github.com/microsoft/typescript-go/internal/jsonrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyncConn manages bidirectional communication with synchronous request handling.
|
||||||
|
// Requests are handled one at a time inline, and outgoing calls are serialized.
|
||||||
|
type SyncConn struct {
|
||||||
|
rwc io.ReadWriteCloser
|
||||||
|
protocol Protocol
|
||||||
|
handler Handler
|
||||||
|
|
||||||
|
// timing, when non-nil, accumulates the wall-clock time spent handling each
|
||||||
|
// request. Clients retrieve the collected data via a getServerTiming request.
|
||||||
|
timing *timingCollector
|
||||||
|
|
||||||
|
// mu serializes all protocol operations (reads and writes).
|
||||||
|
// This ensures that concurrent calls from handler goroutines (e.g., project code
|
||||||
|
// spawning goroutines that invoke filesystem callbacks) don't corrupt the stream.
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSyncConn creates a new sync connection with the given transport and handler.
|
||||||
|
func NewSyncConn(rwc io.ReadWriteCloser, protocol Protocol, handler Handler) *SyncConn {
|
||||||
|
return &SyncConn{
|
||||||
|
rwc: rwc,
|
||||||
|
protocol: protocol,
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCollectTiming enables or disables per-request server processing-time
|
||||||
|
// measurement. When enabled, the connection accumulates timing that clients can
|
||||||
|
// retrieve via a getServerTiming request.
|
||||||
|
func (c *SyncConn) SetCollectTiming(enabled bool) {
|
||||||
|
if enabled {
|
||||||
|
c.timing = newTimingCollector()
|
||||||
|
} else {
|
||||||
|
c.timing = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts processing messages on the connection.
|
||||||
|
// It blocks until the context is cancelled or an error occurs.
|
||||||
|
func (c *SyncConn) Run(ctx context.Context) error {
|
||||||
|
for {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
msg, err := c.protocol.ReadMessage()
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.IsRequest() {
|
||||||
|
c.handleRequest(ctx, msg)
|
||||||
|
} else if msg.IsNotification() {
|
||||||
|
c.handleNotification(ctx, msg)
|
||||||
|
} else {
|
||||||
|
// Responses are not expected in the main loop - they are read inline by Call().
|
||||||
|
return errors.New("api: unexpected response message in sync connection")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleRequest processes an incoming request.
|
||||||
|
func (c *SyncConn) handleRequest(ctx context.Context, msg *Message) {
|
||||||
|
// Intercept the meta-requests for collected server timing before dispatching
|
||||||
|
// to the handler, so they are answered directly and not themselves recorded.
|
||||||
|
switch msg.Method {
|
||||||
|
case string(MethodGetServerTiming):
|
||||||
|
c.mu.Lock()
|
||||||
|
writeErr := c.protocol.WriteResponse(msg.ID, serverTimingSnapshot(c.timing))
|
||||||
|
c.mu.Unlock()
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write server timing response: %v", writeErr))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case string(MethodResetServerTiming):
|
||||||
|
if c.timing != nil {
|
||||||
|
c.timing.reset()
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
writeErr := c.protocol.WriteResponse(msg.ID, nil)
|
||||||
|
c.mu.Unlock()
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write reset server timing response: %v", writeErr))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var result any
|
||||||
|
var err error
|
||||||
|
|
||||||
|
start := time.Time{}
|
||||||
|
if c.timing != nil {
|
||||||
|
start = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recover from panics and convert to error response with stack trace
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
stack := string(debug.Stack())
|
||||||
|
err = fmt.Errorf("panic: %v\n%s", r, stack)
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
writeErr := c.protocol.WriteError(msg.ID, &jsonrpc.ResponseError{
|
||||||
|
Code: jsonrpc.CodeInternalError,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write panic error response: %v (original panic: %v)", writeErr, r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
result, err = c.handler.HandleRequest(ctx, msg.Method, msg.Params)
|
||||||
|
|
||||||
|
if c.timing != nil {
|
||||||
|
c.timing.record(msg.Method, time.Since(start))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
var writeErr error
|
||||||
|
if err != nil {
|
||||||
|
writeErr = c.protocol.WriteError(msg.ID, &jsonrpc.ResponseError{
|
||||||
|
Code: jsonrpc.CodeInternalError,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
writeErr = c.protocol.WriteResponse(msg.ID, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeErr != nil {
|
||||||
|
panic(fmt.Sprintf("api: failed to write response: %v", writeErr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleNotification processes an incoming notification.
|
||||||
|
func (c *SyncConn) handleNotification(ctx context.Context, msg *Message) {
|
||||||
|
_ = c.handler.HandleNotification(ctx, msg.Method, msg.Params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call sends a request to the client and waits for a response.
|
||||||
|
// This method is safe to call from multiple goroutines - calls are serialized.
|
||||||
|
func (c *SyncConn) Call(ctx context.Context, method string, params any) (json.Value, error) {
|
||||||
|
// Serialize all Call operations. This is critical because:
|
||||||
|
// 1. The msgpack protocol uses method names as response IDs
|
||||||
|
// 2. The handler code (project internals) may spawn goroutines that call
|
||||||
|
// filesystem callbacks concurrently
|
||||||
|
// 3. We need to ensure write/read pairs are atomic
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
id := jsonrpc.NewIDString(method)
|
||||||
|
|
||||||
|
if err := c.protocol.WriteRequest(id, method, params); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return nil, ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the response inline.
|
||||||
|
msg, err := c.protocol.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.IsResponse() && msg.ID != nil && msg.ID.String() == method {
|
||||||
|
if msg.Error != nil {
|
||||||
|
return nil, fmt.Errorf("api: remote error [%d]: %s", msg.Error.Code, msg.Error.Message)
|
||||||
|
}
|
||||||
|
return msg.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unexpected message while waiting for response
|
||||||
|
return nil, fmt.Errorf("api: unexpected message while waiting for %q response", method)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify sends a notification to the client (no response expected).
|
||||||
|
func (c *SyncConn) Notify(ctx context.Context, method string, params any) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.protocol.WriteNotification(method, params)
|
||||||
|
}
|
||||||
381
tools/tsgo/internal/api/encoder/decoder.go
Normal file
381
tools/tsgo/internal/api/encoder/decoder.go
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// astDecoder reconstructs real *ast.Node objects from binary-encoded data.
|
||||||
|
type astDecoder struct {
|
||||||
|
raw []byte
|
||||||
|
strTable uint32
|
||||||
|
strData uint32
|
||||||
|
extData uint32
|
||||||
|
nodeOff uint32
|
||||||
|
nodeCount int
|
||||||
|
factory *ast.NodeFactory
|
||||||
|
childBuf []int
|
||||||
|
// Single Go string covering all string data; substrings are zero-alloc slices.
|
||||||
|
allStringData string
|
||||||
|
// Arena for batch-allocating []*ast.Node slices used by NodeLists.
|
||||||
|
nodeArena []*ast.Node
|
||||||
|
// Results
|
||||||
|
nodes []*ast.Node
|
||||||
|
nodeLists []*ast.NodeList
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeSourceFile decodes binary-encoded data into an *ast.SourceFile.
|
||||||
|
func DecodeSourceFile(data []byte) (*ast.SourceFile, error) {
|
||||||
|
node, err := DecodeNodes(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if node.Kind != ast.KindSourceFile {
|
||||||
|
return nil, fmt.Errorf("expected SourceFile root, got %v", node.Kind)
|
||||||
|
}
|
||||||
|
return node.AsSourceFile(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeNodes decodes binary-encoded AST data into a tree of *ast.Node objects.
|
||||||
|
func DecodeNodes(data []byte) (*ast.Node, error) {
|
||||||
|
d, err := newASTDecoder(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.decode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newASTDecoder(data []byte) (*astDecoder, error) {
|
||||||
|
if len(data) < HeaderSize {
|
||||||
|
return nil, fmt.Errorf("data too short for header: %d bytes", len(data))
|
||||||
|
}
|
||||||
|
version := data[HeaderOffsetMetadata+3]
|
||||||
|
if version != ProtocolVersion {
|
||||||
|
return nil, fmt.Errorf("unsupported protocol version %d (expected %d)", version, ProtocolVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
strTable := readLE32(data, HeaderOffsetStringOffsets)
|
||||||
|
strData := readLE32(data, HeaderOffsetStringData)
|
||||||
|
extData := readLE32(data, HeaderOffsetExtendedData)
|
||||||
|
nodeOff := readLE32(data, HeaderOffsetNodes)
|
||||||
|
|
||||||
|
dataLen := uint32(len(data))
|
||||||
|
|
||||||
|
// Validate that all offsets are within the buffer.
|
||||||
|
if strTable > dataLen || strData > dataLen || extData > dataLen || nodeOff > dataLen {
|
||||||
|
return nil, fmt.Errorf("invalid AST header offsets: offsets exceed data length (%d)", dataLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate monotonic non-decreasing order of regions.
|
||||||
|
if !(strTable <= strData && strData <= extData && extData <= nodeOff) {
|
||||||
|
return nil, fmt.Errorf("invalid AST header offsets: expected strTable <= strData <= extData <= nodeOff (got %d, %d, %d, %d)", strTable, strData, extData, nodeOff)
|
||||||
|
}
|
||||||
|
|
||||||
|
d := &astDecoder{
|
||||||
|
raw: data,
|
||||||
|
strTable: strTable,
|
||||||
|
strData: strData,
|
||||||
|
extData: extData,
|
||||||
|
nodeOff: nodeOff,
|
||||||
|
factory: ast.NewNodeFactory(ast.NodeFactoryHooks{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
d.nodeCount = (len(data) - int(d.nodeOff)) / NodeSize
|
||||||
|
|
||||||
|
// Convert entire string data region to a single Go string upfront.
|
||||||
|
// Substringing a Go string shares the backing array, so subsequent
|
||||||
|
// getString calls produce substrings with zero allocations.
|
||||||
|
d.allStringData = string(data[d.strData:])
|
||||||
|
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocNodeSlice returns a zero-length slice with the given capacity, backed by
|
||||||
|
// the pre-allocated nodeArena. This avoids a heap allocation per NodeList.
|
||||||
|
func (d *astDecoder) allocNodeSlice(capacity int) []*ast.Node {
|
||||||
|
start := len(d.nodeArena)
|
||||||
|
d.nodeArena = d.nodeArena[:start+capacity]
|
||||||
|
return d.nodeArena[start : start : start+capacity]
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeField reads a uint32 field from node i at the given field offset.
|
||||||
|
func (d *astDecoder) nodeField(i int, field int) uint32 {
|
||||||
|
return readLE32(d.raw, int(d.nodeOff)+i*NodeSize+field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) getString(idx uint32) string {
|
||||||
|
offBase := int(d.strTable) + int(idx)*4
|
||||||
|
start := readLE32(d.raw, offBase)
|
||||||
|
end := readLE32(d.raw, offBase+4)
|
||||||
|
return d.allStringData[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
// collectChildren returns indices of direct children of node i.
|
||||||
|
// The returned slice is reused across calls; callers must not retain it.
|
||||||
|
func (d *astDecoder) collectChildren(i int) []int {
|
||||||
|
d.childBuf = d.childBuf[:0]
|
||||||
|
if i+1 >= d.nodeCount {
|
||||||
|
return d.childBuf
|
||||||
|
}
|
||||||
|
firstChild := i + 1
|
||||||
|
if d.nodeField(firstChild, NodeOffsetParent) != uint32(i) {
|
||||||
|
return d.childBuf
|
||||||
|
}
|
||||||
|
d.childBuf = append(d.childBuf, firstChild)
|
||||||
|
next := int(d.nodeField(firstChild, NodeOffsetNext))
|
||||||
|
for next != 0 {
|
||||||
|
d.childBuf = append(d.childBuf, next)
|
||||||
|
next = int(d.nodeField(next, NodeOffsetNext))
|
||||||
|
}
|
||||||
|
return d.childBuf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decode() (*ast.Node, error) {
|
||||||
|
if d.nodeCount < 2 {
|
||||||
|
return nil, errors.New("no nodes to decode")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.nodes = make([]*ast.Node, d.nodeCount)
|
||||||
|
d.nodeLists = make([]*ast.NodeList, d.nodeCount)
|
||||||
|
// Pre-allocate arena for NodeList child slices. Each node can appear as a
|
||||||
|
// child at most once, so nodeCount is an upper bound on total child pointers.
|
||||||
|
d.nodeArena = make([]*ast.Node, 0, d.nodeCount)
|
||||||
|
|
||||||
|
// Process bottom-up so children exist before parents.
|
||||||
|
for i := d.nodeCount - 1; i >= 1; i-- {
|
||||||
|
kind := d.nodeField(i, NodeOffsetKind)
|
||||||
|
pos := d.nodeField(i, NodeOffsetPos)
|
||||||
|
end := d.nodeField(i, NodeOffsetEnd)
|
||||||
|
data := d.nodeField(i, NodeOffsetData)
|
||||||
|
childIndices := d.collectChildren(i)
|
||||||
|
|
||||||
|
if kind == SyntaxKindNodeList {
|
||||||
|
childNodes := d.allocNodeSlice(len(childIndices))
|
||||||
|
for _, ci := range childIndices {
|
||||||
|
if d.nodes[ci] != nil {
|
||||||
|
childNodes = append(childNodes, d.nodes[ci])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nl := d.factory.NewNodeList(childNodes)
|
||||||
|
nl.Loc = core.NewTextRange(int(pos), int(end))
|
||||||
|
d.nodeLists[i] = nl
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := d.createNode(ast.Kind(kind), data, childIndices)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("at node %d (kind %v): %w", i, ast.Kind(kind), err)
|
||||||
|
}
|
||||||
|
node.Loc = core.NewTextRange(int(pos), int(end))
|
||||||
|
node.Flags = ast.NodeFlags(d.nodeField(i, NodeOffsetFlags))
|
||||||
|
d.nodes[i] = node
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.nodes[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getModifierList creates a *ast.ModifierList from a child index that is a NodeList.
|
||||||
|
func (d *astDecoder) getModifierList(ci int) *ast.ModifierList {
|
||||||
|
nl := d.nodeLists[ci]
|
||||||
|
if nl == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ml := d.factory.NewModifierList(nl.Nodes)
|
||||||
|
ml.Loc = nl.Loc
|
||||||
|
return ml
|
||||||
|
}
|
||||||
|
|
||||||
|
// childIterator helps walk through children based on a bitmask.
|
||||||
|
type childIterator struct {
|
||||||
|
indices []int
|
||||||
|
pos int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChildIter(indices []int) childIterator {
|
||||||
|
return childIterator{indices: indices}
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns the index of the next child, advancing the position.
|
||||||
|
func (it *childIterator) next() int {
|
||||||
|
if it.pos >= len(it.indices) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ci := it.indices[it.pos]
|
||||||
|
it.pos++
|
||||||
|
return ci
|
||||||
|
}
|
||||||
|
|
||||||
|
// nextIf returns the index of the next child if the corresponding mask bit is set.
|
||||||
|
func (it *childIterator) nextIf(mask uint8, bit uint8) int {
|
||||||
|
if mask&(1<<bit) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return it.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) nodeAt(ci int) *ast.Node {
|
||||||
|
if ci == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.nodes[ci]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) nodeListAt(ci int) *ast.NodeList {
|
||||||
|
if ci == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.nodeLists[ci]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) modifierListAt(ci int) *ast.ModifierList {
|
||||||
|
if ci == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.getModifierList(ci)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) createNode(kind ast.Kind, data uint32, childIndices []int) (*ast.Node, error) {
|
||||||
|
dataType := data & NodeDataTypeMask
|
||||||
|
commonData := uint8((data >> 24) & 0x3f)
|
||||||
|
|
||||||
|
switch dataType {
|
||||||
|
case NodeDataTypeString:
|
||||||
|
return d.createStringNode(kind, data, commonData)
|
||||||
|
case NodeDataTypeExtendedData:
|
||||||
|
return d.createExtendedNode(kind, data, childIndices, commonData)
|
||||||
|
default:
|
||||||
|
return d.createChildrenNode(kind, data, childIndices, commonData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_SourceFile(data uint32, childIndices []int, commonData uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
fileNameIdx := readLE32(d.raw, extOff+4)
|
||||||
|
pathIdx := readLE32(d.raw, extOff+8)
|
||||||
|
text := d.getString(textIdx)
|
||||||
|
fileName := d.getString(fileNameIdx)
|
||||||
|
path := d.getString(pathIdx)
|
||||||
|
|
||||||
|
// Recover parse options from header.
|
||||||
|
parseOpts := readLE32(d.raw, HeaderOffsetParseOptions)
|
||||||
|
opts := ast.SourceFileParseOptions{
|
||||||
|
FileName: fileName,
|
||||||
|
Path: tspath.Path(path),
|
||||||
|
ExternalModuleIndicatorOptions: ast.ExternalModuleIndicatorOptions{
|
||||||
|
JSX: parseOpts&1 != 0,
|
||||||
|
Force: parseOpts&2 != 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect children: first is statements NodeList, second is EndOfFile.
|
||||||
|
var stmts *ast.NodeList
|
||||||
|
var endOfFile *ast.Node
|
||||||
|
for _, ci := range childIndices {
|
||||||
|
if d.nodeField(ci, NodeOffsetKind) == SyntaxKindNodeList {
|
||||||
|
stmts = d.nodeListAt(ci)
|
||||||
|
} else if d.nodes[ci] != nil && d.nodes[ci].Kind == ast.KindEndOfFile {
|
||||||
|
endOfFile = d.nodes[ci]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if endOfFile == nil {
|
||||||
|
endOfFile = d.factory.NewToken(ast.KindEndOfFile)
|
||||||
|
}
|
||||||
|
return d.factory.NewSourceFile(opts, text, stmts, endOfFile), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_TemplateHead(data uint32, childIndices []int, commonData uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
rawTextIdx := readLE32(d.raw, extOff+4)
|
||||||
|
flags := readLE32(d.raw, extOff+8)
|
||||||
|
return d.factory.NewTemplateHead(d.getString(textIdx), d.getString(rawTextIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_TemplateMiddle(data uint32, childIndices []int, commonData uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
rawTextIdx := readLE32(d.raw, extOff+4)
|
||||||
|
flags := readLE32(d.raw, extOff+8)
|
||||||
|
return d.factory.NewTemplateMiddle(d.getString(textIdx), d.getString(rawTextIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_TemplateTail(data uint32, childIndices []int, commonData uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
rawTextIdx := readLE32(d.raw, extOff+4)
|
||||||
|
flags := readLE32(d.raw, extOff+8)
|
||||||
|
return d.factory.NewTemplateTail(d.getString(textIdx), d.getString(rawTextIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) singleChild(childIndices []int) *ast.Node {
|
||||||
|
if len(childIndices) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.nodes[childIndices[0]]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) singleNodeListChild(childIndices []int) *ast.NodeList {
|
||||||
|
if len(childIndices) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.nodeLists[childIndices[0]]
|
||||||
|
}
|
||||||
|
|
||||||
|
func readLE32(data []byte, offset int) uint32 {
|
||||||
|
if offset < 0 || offset+4 > len(data) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return binary.LittleEndian.Uint32(data[offset : offset+4])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand-written commonData decoding functions. Each extracts the original values
|
||||||
|
// from the 6-bit commonData that were packed by the corresponding
|
||||||
|
// getNodeCommonData_* function.
|
||||||
|
|
||||||
|
func decodeNodeCommonData_SyntheticExpression(_ uint8) (any, bool) {
|
||||||
|
panic("SyntheticExpression should never be decoded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand-written extended data decoding functions for literal nodes.
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_StringLiteral(data uint32, _ []int, _ uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
flags := readLE32(d.raw, extOff+4)
|
||||||
|
return d.factory.NewStringLiteral(d.getString(textIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_NumericLiteral(data uint32, _ []int, _ uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
flags := readLE32(d.raw, extOff+4)
|
||||||
|
return d.factory.NewNumericLiteral(d.getString(textIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_BigIntLiteral(data uint32, _ []int, _ uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
flags := readLE32(d.raw, extOff+4)
|
||||||
|
return d.factory.NewBigIntLiteral(d.getString(textIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_RegularExpressionLiteral(data uint32, _ []int, _ uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
flags := readLE32(d.raw, extOff+4)
|
||||||
|
return d.factory.NewRegularExpressionLiteral(d.getString(textIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *astDecoder) decodeExtendedData_NoSubstitutionTemplateLiteral(data uint32, _ []int, _ uint8) (*ast.Node, error) {
|
||||||
|
extOff := int(d.extData) + int(data&NodeDataStringIndexMask)
|
||||||
|
textIdx := readLE32(d.raw, extOff)
|
||||||
|
flags := readLE32(d.raw, extOff+4)
|
||||||
|
return d.factory.NewNoSubstitutionTemplateLiteral(d.getString(textIdx), ast.TokenFlags(flags)), nil
|
||||||
|
}
|
||||||
1140
tools/tsgo/internal/api/encoder/decoder_generated.go
Normal file
1140
tools/tsgo/internal/api/encoder/decoder_generated.go
Normal file
File diff suppressed because it is too large
Load Diff
450
tools/tsgo/internal/api/encoder/decoder_test.go
Normal file
450
tools/tsgo/internal/api/encoder/decoder_test.go
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
package encoder_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/api/encoder"
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/parser"
|
||||||
|
"github.com/microsoft/typescript-go/internal/repo"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseSourceFile(code string) *ast.SourceFile {
|
||||||
|
return parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/test.ts",
|
||||||
|
Path: "/test.ts",
|
||||||
|
}, code, core.ScriptKindTS)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_Basic(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let x = 1;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, decoded.AsNode().Kind, ast.KindSourceFile)
|
||||||
|
assert.Equal(t, decoded.FileName(), "/test.ts")
|
||||||
|
assert.Equal(t, decoded.Text(), "let x = 1;")
|
||||||
|
assert.Assert(t, decoded.Statements != nil)
|
||||||
|
assert.Assert(t, decoded.EndOfFileToken != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_Statements(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let a = 1;\nlet b = 2;\nlet c = 3;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, len(decoded.Statements.Nodes), 3)
|
||||||
|
for i, stmt := range decoded.Statements.Nodes {
|
||||||
|
assert.Equal(t, stmt.Kind, ast.KindVariableStatement, "statement %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_VariableDeclaration(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let x = 1;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
varStmt := decoded.Statements.Nodes[0].AsVariableStatement()
|
||||||
|
assert.Assert(t, varStmt.DeclarationList != nil)
|
||||||
|
declList := varStmt.DeclarationList.AsVariableDeclarationList()
|
||||||
|
assert.Assert(t, declList.Declarations != nil)
|
||||||
|
assert.Equal(t, len(declList.Declarations.Nodes), 1)
|
||||||
|
|
||||||
|
decl := declList.Declarations.Nodes[0].AsVariableDeclaration()
|
||||||
|
assert.Equal(t, decl.Name().Kind, ast.KindIdentifier)
|
||||||
|
assert.Equal(t, decl.Name().AsIdentifier().Text, "x")
|
||||||
|
assert.Assert(t, decl.Initializer != nil)
|
||||||
|
assert.Equal(t, decl.Initializer.Kind, ast.KindNumericLiteral)
|
||||||
|
assert.Equal(t, decl.Initializer.AsNumericLiteral().Text, "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_VariableDeclarationListFlags(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
code string
|
||||||
|
expected ast.NodeFlags
|
||||||
|
}{
|
||||||
|
{"const", "const x = 1;", ast.NodeFlagsConst},
|
||||||
|
{"let", "let x = 1;", ast.NodeFlagsLet},
|
||||||
|
{"var", "var x = 1;", ast.NodeFlagsNone},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile(tt.code)
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
declList := decoded.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList()
|
||||||
|
got := declList.Flags & (ast.NodeFlagsLet | ast.NodeFlagsConst)
|
||||||
|
assert.Equal(t, got, tt.expected, "flags for %q: got %d, want %d", tt.code, got, tt.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_FunctionDeclaration(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("function add(a: number, b: number): number { return a + b; }")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
funcDecl := decoded.Statements.Nodes[0].AsFunctionDeclaration()
|
||||||
|
assert.Assert(t, funcDecl.Name() != nil)
|
||||||
|
assert.Equal(t, funcDecl.Name().AsIdentifier().Text, "add")
|
||||||
|
assert.Assert(t, funcDecl.Parameters != nil)
|
||||||
|
assert.Equal(t, len(funcDecl.Parameters.Nodes), 2)
|
||||||
|
assert.Assert(t, funcDecl.Type != nil)
|
||||||
|
assert.Assert(t, funcDecl.Body != nil)
|
||||||
|
|
||||||
|
param0 := funcDecl.Parameters.Nodes[0].AsParameterDeclaration()
|
||||||
|
assert.Equal(t, param0.Name().AsIdentifier().Text, "a")
|
||||||
|
assert.Assert(t, param0.Type != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_ImportDeclaration(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile(`import { bar } from "bar";`)
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
imp := decoded.Statements.Nodes[0].AsImportDeclaration()
|
||||||
|
assert.Assert(t, imp.ImportClause != nil)
|
||||||
|
assert.Assert(t, imp.ModuleSpecifier != nil)
|
||||||
|
assert.Equal(t, imp.ModuleSpecifier.AsStringLiteral().Text, "bar")
|
||||||
|
|
||||||
|
clause := imp.ImportClause.AsImportClause()
|
||||||
|
assert.Assert(t, clause.NamedBindings != nil)
|
||||||
|
namedImports := clause.NamedBindings.AsNamedImports()
|
||||||
|
assert.Assert(t, namedImports.Elements != nil)
|
||||||
|
assert.Equal(t, len(namedImports.Elements.Nodes), 1)
|
||||||
|
spec := namedImports.Elements.Nodes[0].AsImportSpecifier()
|
||||||
|
assert.Equal(t, spec.Name().AsIdentifier().Text, "bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_IfStatement(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("if (true) { } else { }")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
ifStmt := decoded.Statements.Nodes[0].AsIfStatement()
|
||||||
|
assert.Assert(t, ifStmt.Expression != nil)
|
||||||
|
assert.Assert(t, ifStmt.ThenStatement != nil)
|
||||||
|
assert.Assert(t, ifStmt.ElseStatement != nil)
|
||||||
|
assert.Equal(t, ifStmt.ThenStatement.Kind, ast.KindBlock)
|
||||||
|
assert.Equal(t, ifStmt.ElseStatement.Kind, ast.KindBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_TemplateExpression(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let x = `hello ${name} world`;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
varDecl := decoded.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0].AsVariableDeclaration()
|
||||||
|
tmplExpr := varDecl.Initializer.AsTemplateExpression()
|
||||||
|
assert.Assert(t, tmplExpr.Head != nil)
|
||||||
|
assert.Equal(t, tmplExpr.Head.AsTemplateHead().Text, "hello ")
|
||||||
|
assert.Assert(t, tmplExpr.TemplateSpans != nil)
|
||||||
|
assert.Equal(t, len(tmplExpr.TemplateSpans.Nodes), 1)
|
||||||
|
|
||||||
|
span := tmplExpr.TemplateSpans.Nodes[0].AsTemplateSpan()
|
||||||
|
assert.Assert(t, span.Expression != nil)
|
||||||
|
assert.Equal(t, span.Expression.Kind, ast.KindIdentifier)
|
||||||
|
assert.Assert(t, span.Literal != nil)
|
||||||
|
assert.Equal(t, span.Literal.AsTemplateTail().Text, " world")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_ExportModifier(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("export function foo() {}")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
funcDecl := decoded.Statements.Nodes[0].AsFunctionDeclaration()
|
||||||
|
assert.Assert(t, funcDecl.Modifiers() != nil)
|
||||||
|
assert.Equal(t, len(funcDecl.Modifiers().Nodes), 1)
|
||||||
|
assert.Equal(t, funcDecl.Modifiers().Nodes[0].Kind, ast.KindExportKeyword)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_Positions(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
code := "let x = 1;"
|
||||||
|
sf := parseSourceFile(code)
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, decoded.AsNode().Pos(), 0)
|
||||||
|
assert.Equal(t, decoded.AsNode().End(), len(code))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_ClassDeclaration(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("class Foo { bar(): void {} }")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
classDecl := decoded.Statements.Nodes[0].AsClassDeclaration()
|
||||||
|
assert.Assert(t, classDecl.Name() != nil)
|
||||||
|
assert.Equal(t, classDecl.Name().AsIdentifier().Text, "Foo")
|
||||||
|
assert.Assert(t, classDecl.Members != nil)
|
||||||
|
assert.Equal(t, len(classDecl.Members.Nodes), 1)
|
||||||
|
assert.Equal(t, classDecl.Members.Nodes[0].Kind, ast.KindMethodDeclaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeNodes_SubtreeRoundTrip(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("function greet(name: string) { return `Hello, ${name}!`; }")
|
||||||
|
|
||||||
|
var funcNode *ast.Node
|
||||||
|
visitor := &ast.NodeVisitor{}
|
||||||
|
visitor.Visit = func(node *ast.Node) *ast.Node {
|
||||||
|
if node.Kind == ast.KindFunctionDeclaration && funcNode == nil {
|
||||||
|
funcNode = node
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
visitor.VisitEachChild(sf.AsNode())
|
||||||
|
assert.Assert(t, funcNode != nil)
|
||||||
|
|
||||||
|
buf, _, err := encoder.EncodeNode(funcNode, sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeNodes(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, decoded.Kind, ast.KindFunctionDeclaration)
|
||||||
|
funcDecl := decoded.AsFunctionDeclaration()
|
||||||
|
assert.Assert(t, funcDecl.Name() != nil)
|
||||||
|
assert.Equal(t, funcDecl.Name().AsIdentifier().Text, "greet")
|
||||||
|
assert.Assert(t, funcDecl.Parameters != nil)
|
||||||
|
assert.Equal(t, len(funcDecl.Parameters.Nodes), 1)
|
||||||
|
assert.Assert(t, funcDecl.Body != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_BinaryExpression(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let x = 1 + 2;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decl := decoded.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0].AsVariableDeclaration()
|
||||||
|
binExpr := decl.Initializer.AsBinaryExpression()
|
||||||
|
assert.Assert(t, binExpr.Left != nil)
|
||||||
|
assert.Assert(t, binExpr.Right != nil)
|
||||||
|
assert.Assert(t, binExpr.OperatorToken != nil)
|
||||||
|
assert.Equal(t, binExpr.Left.Kind, ast.KindNumericLiteral)
|
||||||
|
assert.Equal(t, binExpr.Right.Kind, ast.KindNumericLiteral)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_KeywordExpressions(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// "this" must decode as KeywordExpression, not Token, or the printer panics
|
||||||
|
sf := parseSourceFile("const x = this;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
// Navigate: const x = this -> VariableStatement -> declaration -> initializer
|
||||||
|
decl := decoded.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0].AsVariableDeclaration()
|
||||||
|
thisExpr := decl.Initializer
|
||||||
|
assert.Equal(t, thisExpr.Kind, ast.KindThisKeyword)
|
||||||
|
// This would panic if decoded as Token instead of KeywordExpression
|
||||||
|
assert.Assert(t, thisExpr.AsKeywordExpression() != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_EmptyModuleBlock(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("namespace N { }")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
// Navigate: namespace N { } -> ModuleDeclaration -> ModuleBlock
|
||||||
|
mod := decoded.Statements.Nodes[0].AsModuleDeclaration()
|
||||||
|
assert.Assert(t, mod.Body != nil)
|
||||||
|
block := mod.Body.AsModuleBlock()
|
||||||
|
// Statements must be non-nil even when empty, otherwise the printer panics
|
||||||
|
assert.Assert(t, block.Statements != nil)
|
||||||
|
assert.Equal(t, len(block.Statements.Nodes), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_EmptyBlockAndParams(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Empty blocks and parameter lists must decode with non-nil NodeLists (not nil),
|
||||||
|
// matching parser behavior. Previously the decoder left them nil, crashing the printer.
|
||||||
|
sf := parseSourceFile("function foo() {}")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
funcDecl := decoded.Statements.Nodes[0].AsFunctionDeclaration()
|
||||||
|
assert.Assert(t, funcDecl.Parameters != nil, "FunctionDeclaration.Parameters must be non-nil for foo()")
|
||||||
|
assert.Equal(t, len(funcDecl.Parameters.Nodes), 0)
|
||||||
|
assert.Assert(t, funcDecl.Body != nil)
|
||||||
|
block := funcDecl.Body.AsBlock()
|
||||||
|
assert.Assert(t, block.Statements != nil, "Block.Statements must be non-nil for empty blocks")
|
||||||
|
assert.Equal(t, len(block.Statements.Nodes), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_ArrowFunctionEmptyParams(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// `() => {}` must decode with non-nil Parameters (empty NodeList),
|
||||||
|
// matching parser behavior. Previously the decoder left it nil, crashing the printer.
|
||||||
|
sf := parseSourceFile("const f = () => {};")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decl := decoded.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0].AsVariableDeclaration()
|
||||||
|
arrow := decl.Initializer.AsArrowFunction()
|
||||||
|
assert.Assert(t, arrow.Parameters != nil, "ArrowFunction.Parameters must be non-nil for () => {}")
|
||||||
|
assert.Equal(t, len(arrow.Parameters.Nodes), 0)
|
||||||
|
assert.Assert(t, arrow.Body != nil)
|
||||||
|
block := arrow.Body.AsBlock()
|
||||||
|
assert.Assert(t, block.Statements != nil, "Block.Statements must be non-nil for empty body")
|
||||||
|
assert.Equal(t, len(block.Statements.Nodes), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_FunctionExpressionEmptyParams(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// `function() {}` must decode with non-nil Parameters (empty NodeList).
|
||||||
|
sf := parseSourceFile("const f = function() {};")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decl := decoded.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0].AsVariableDeclaration()
|
||||||
|
funcExpr := decl.Initializer.AsFunctionExpression()
|
||||||
|
assert.Assert(t, funcExpr.Parameters != nil, "FunctionExpression.Parameters must be non-nil for function() {}")
|
||||||
|
assert.Equal(t, len(funcExpr.Parameters.Nodes), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_PostfixUnaryOperator(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let i = 0; i++;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
exprStmt := decoded.Statements.Nodes[1].AsExpressionStatement()
|
||||||
|
postfix := exprStmt.Expression.AsPostfixUnaryExpression()
|
||||||
|
assert.Equal(t, postfix.Operator, ast.KindPlusPlusToken)
|
||||||
|
assert.Equal(t, postfix.Operand.Kind, ast.KindIdentifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_PrefixUnaryOperator(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let x = true; !x;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
exprStmt := decoded.Statements.Nodes[1].AsExpressionStatement()
|
||||||
|
prefix := exprStmt.Expression.AsPrefixUnaryExpression()
|
||||||
|
assert.Equal(t, prefix.Operator, ast.KindExclamationToken)
|
||||||
|
assert.Equal(t, prefix.Operand.Kind, ast.KindIdentifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeSourceFile_PostfixDecrement(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sf := parseSourceFile("let n = 5; n--;")
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
decoded, err := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
exprStmt := decoded.Statements.Nodes[1].AsExpressionStatement()
|
||||||
|
postfix := exprStmt.Expression.AsPostfixUnaryExpression()
|
||||||
|
assert.Equal(t, postfix.Operator, ast.KindMinusMinusToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeSourceFile(b *testing.B) {
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(b)
|
||||||
|
filePath := filepath.Join(repo.TypeScriptSubmodulePath(), "src/compiler/checker.ts")
|
||||||
|
fileContent, err := os.ReadFile(filePath)
|
||||||
|
assert.NilError(b, err)
|
||||||
|
code := string(fileContent)
|
||||||
|
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/checker.ts",
|
||||||
|
Path: "/checker.ts",
|
||||||
|
}, code, core.ScriptKindTS)
|
||||||
|
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sourceFile)
|
||||||
|
assert.NilError(b, err)
|
||||||
|
|
||||||
|
b.Run("parse", func(b *testing.B) {
|
||||||
|
for b.Loop() {
|
||||||
|
parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/checker.ts",
|
||||||
|
Path: "/checker.ts",
|
||||||
|
}, code, core.ScriptKindTS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("decode", func(b *testing.B) {
|
||||||
|
for b.Loop() {
|
||||||
|
_, decodeErr := encoder.DecodeSourceFile(buf)
|
||||||
|
assert.NilError(b, decodeErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
844
tools/tsgo/internal/api/encoder/encoder.go
Normal file
844
tools/tsgo/internal/api/encoder/encoder.go
Normal file
@@ -0,0 +1,844 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/zeebo/xxh3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if ast.KindLastUnaryOperator > 0x3f {
|
||||||
|
panic(fmt.Sprintf("KindLastUnaryOperator (%d) exceeds the 6-bit commonData capacity (max 63)", ast.KindLastUnaryOperator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeOffsetKind = iota * 4
|
||||||
|
NodeOffsetPos
|
||||||
|
NodeOffsetEnd
|
||||||
|
NodeOffsetNext
|
||||||
|
NodeOffsetParent
|
||||||
|
NodeOffsetData
|
||||||
|
NodeOffsetFlags
|
||||||
|
// NodeSize is the number of bytes that represents a single node in the encoded format.
|
||||||
|
NodeSize
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeDataTypeChildren uint32 = iota << 30
|
||||||
|
NodeDataTypeString
|
||||||
|
NodeDataTypeExtendedData
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeDataTypeMask uint32 = 0xc0_00_00_00
|
||||||
|
NodeDataChildMask uint32 = 0x00_00_00_ff
|
||||||
|
NodeDataStringIndexMask uint32 = 0x00_ff_ff_ff
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SyntaxKindNodeList uint32 = 1<<32 - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
HeaderOffsetMetadata = iota * 4
|
||||||
|
HeaderOffsetHashLo0
|
||||||
|
HeaderOffsetHashLo1
|
||||||
|
HeaderOffsetHashHi0
|
||||||
|
HeaderOffsetHashHi1
|
||||||
|
HeaderOffsetParseOptions
|
||||||
|
HeaderOffsetStringOffsets
|
||||||
|
HeaderOffsetStringData
|
||||||
|
HeaderOffsetExtendedData
|
||||||
|
HeaderOffsetStructuredData
|
||||||
|
HeaderOffsetNodes
|
||||||
|
HeaderSize
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProtocolVersion uint8 = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Source File Binary Format
|
||||||
|
// =========================
|
||||||
|
//
|
||||||
|
// The following defines a protocol for serializing TypeScript SourceFile objects to a compact binary format. All integer
|
||||||
|
// values are little-endian.
|
||||||
|
//
|
||||||
|
// Overview
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// The format comprises seven sections:
|
||||||
|
//
|
||||||
|
// | Section | Length | Description |
|
||||||
|
// | ------------------ | ------------------ | ----------------------------------------------------------------------------------------------- |
|
||||||
|
// | Header | 44 bytes | Contains the content hash, parse options, flags, and byte offsets to the start of each section. |
|
||||||
|
// | String offsets | 8 bytes per string | Pairs of starting byte offsets and ending byte offsets into the **string data** section. |
|
||||||
|
// | String data | variable | UTF-8 encoded string data. |
|
||||||
|
// | Extended node data | variable | Extra data for some kinds of nodes. |
|
||||||
|
// | Structured data | variable | Msgpack-encoded metadata blobs (e.g. file references). |
|
||||||
|
// | Nodes | 28 bytes per node | Defines the AST structure of the file, with references to strings and extended data. |
|
||||||
|
//
|
||||||
|
// Header (44 bytes)
|
||||||
|
// -----------------
|
||||||
|
//
|
||||||
|
// The header contains the following fields:
|
||||||
|
//
|
||||||
|
// | Byte offset | Type | Field |
|
||||||
|
// | ----------- | --------- | ------------------------------------------------- |
|
||||||
|
// | 0 | uint8 | Protocol version |
|
||||||
|
// | 1-3 | | Reserved |
|
||||||
|
// | 4-19 | uint128 | Source file content hash (xxh3, LE) |
|
||||||
|
// | 20-23 | uint32 | Parse options (bitmask; bit 0: JSX, bit 1: Force) |
|
||||||
|
// | 24-27 | uint32 | Byte offset to string offsets section |
|
||||||
|
// | 28-31 | uint32 | Byte offset to string data section |
|
||||||
|
// | 32-35 | uint32 | Byte offset to extended node data section |
|
||||||
|
// | 36-39 | uint32 | Byte offset to structured data section |
|
||||||
|
// | 40-43 | uint32 | Byte offset to nodes section |
|
||||||
|
//
|
||||||
|
// String offsets (8 bytes per string)
|
||||||
|
// -----------------------------------
|
||||||
|
//
|
||||||
|
// Each string offset entry consists of two 4-byte unsigned integers, representing the start and end byte offsets into the
|
||||||
|
// **string data** section.
|
||||||
|
//
|
||||||
|
// String data (variable)
|
||||||
|
// ----------------------
|
||||||
|
//
|
||||||
|
// The string data section contains UTF-8 encoded string data, with WTF-8 used for JS strings containing lone UTF-16
|
||||||
|
// surrogates. In typical cases, the entirety of the string data is the source file text, and individual nodes with
|
||||||
|
// string properties reference their positional slice of the file text. In cases where a node's string property is not
|
||||||
|
// equal to the slice of file text at its position, the unique string is appended to the string data section after the
|
||||||
|
// file text.
|
||||||
|
//
|
||||||
|
// Extended node data (variable)
|
||||||
|
// -----------------------------
|
||||||
|
//
|
||||||
|
// The extended node data section contains additional data for specific node types. The length and meaning of each entry
|
||||||
|
// is defined by the node type.
|
||||||
|
//
|
||||||
|
// Currently, the only node types that use this section are `TemplateHead`, `TemplateMiddle`, `TemplateTail`, and
|
||||||
|
// `SourceFile`. The extended data format for the first three is:
|
||||||
|
//
|
||||||
|
// | Byte offset | Type | Field |
|
||||||
|
// | ----------- | ------ | ------------------------------------------------ |
|
||||||
|
// | 0-4 | uint32 | Index of `text` in the string offsets section |
|
||||||
|
// | 4-8 | uint32 | Index of `rawText` in the string offsets section |
|
||||||
|
// | 8-12 | uint32 | Value of `templateFlags` |
|
||||||
|
//
|
||||||
|
// and for `SourceFile` is:
|
||||||
|
//
|
||||||
|
// | Byte offset | Type | Field |
|
||||||
|
// | ----------- | ------ | -------------------------------------------------------------- |
|
||||||
|
// | 0-4 | uint32 | Index of `text` in the string offsets section |
|
||||||
|
// | 4-8 | uint32 | Index of `fileName` in the string offsets section |
|
||||||
|
// | 8-12 | uint32 | Index of `path` in the string offsets section |
|
||||||
|
// | 12-16 | uint32 | Value of `languageVariant` |
|
||||||
|
// | 16-20 | uint32 | Value of `scriptKind` |
|
||||||
|
// | 20-24 | uint32 | Byte offset of `referencedFiles` in structured data section |
|
||||||
|
// | 24-28 | uint32 | Byte offset of `typeReferenceDirectives` in structured data |
|
||||||
|
// | 28-32 | uint32 | Byte offset of `libReferenceDirectives` in structured data |
|
||||||
|
// | 32-36 | uint32 | Byte offset of `imports` node index array in structured data |
|
||||||
|
// | 36-40 | uint32 | Byte offset of `moduleAugmentations` node index array |
|
||||||
|
// | 40-44 | uint32 | Byte offset of `ambientModuleNames` string array |
|
||||||
|
// | 44-48 | uint32 | Node index of `externalModuleIndicator` (0 = nil) |
|
||||||
|
//
|
||||||
|
// Structured data (variable)
|
||||||
|
// --------------------------
|
||||||
|
//
|
||||||
|
// The structured data section contains msgpack-encoded metadata blobs. Each blob is a self-contained
|
||||||
|
// msgpack value. File reference arrays use the following tuple format:
|
||||||
|
//
|
||||||
|
// [pos: uint, end: uint, fileName: string, resolutionMode: uint, preserve: bool]
|
||||||
|
//
|
||||||
|
// Node index arrays (imports, moduleAugmentations) are msgpack arrays of uint values, where each
|
||||||
|
// value is a node index into the nodes section. String arrays (ambientModuleNames) are msgpack
|
||||||
|
// arrays of string values.
|
||||||
|
//
|
||||||
|
// An offset of 0xFFFFFFFF indicates no data (empty array).
|
||||||
|
//
|
||||||
|
// Nodes (28 bytes per node)
|
||||||
|
// -------------------------
|
||||||
|
//
|
||||||
|
// The nodes section contains the AST structure of the file. Nodes are represented in a flat array in source order,
|
||||||
|
// heavily inspired by https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-11/. Each node has the following
|
||||||
|
// structure:
|
||||||
|
//
|
||||||
|
// | Byte offset | Type | Field |
|
||||||
|
// | ----------- | ------ | -------------------------- |
|
||||||
|
// | 0-4 | uint32 | Kind |
|
||||||
|
// | 4-8 | uint32 | Pos |
|
||||||
|
// | 8-12 | uint32 | End |
|
||||||
|
// | 12-16 | uint32 | Node index of next sibling |
|
||||||
|
// | 16-20 | uint32 | Node index of parent |
|
||||||
|
// | 20-24 | | Node data |
|
||||||
|
// | 24-28 | uint32 | Node flags |
|
||||||
|
//
|
||||||
|
// The first 28 bytes of the nodes section are zeros representing a nil node, such that nodes without a parent or next
|
||||||
|
// sibling can unambiuously use `0` for those indices.
|
||||||
|
//
|
||||||
|
// NodeLists are represented as normal nodes with the special `kind` value `0xff_ff_ff_ff`. They are considered the parent
|
||||||
|
// of their contents in the encoded format. A client reconstructing an AST similar to TypeScript's internal representation
|
||||||
|
// should instead set the `parent` pointers of a NodeList's children to the NodeList's parent. A NodeList's `data` field
|
||||||
|
// is the uint32 length of the list, and does not use one of the data types described below.
|
||||||
|
//
|
||||||
|
// For node types other than NodeList, the node data field encodes one of the following, determined by the first 2 bits of
|
||||||
|
// the field:
|
||||||
|
//
|
||||||
|
// | Value | Data type | Description |
|
||||||
|
// | ----- | --------- | ------------------------------------------------------------------------------------ |
|
||||||
|
// | 0b00 | Children | Disambiguates which named properties of the node its children should be assigned to. |
|
||||||
|
// | 0b01 | String | The index of the node's string property in the **string offsets** section. |
|
||||||
|
// | 0b10 | Extended | The byte offset of the node's extended data into the **extended node data** section. |
|
||||||
|
// | 0b11 | Reserved | Reserved for future use. |
|
||||||
|
//
|
||||||
|
// In all node data types, the remaining 6 bits of the first byte are used to encode small values specific to the node
|
||||||
|
// type. For most node types, these are individual boolean flags. For unary expressions, all 6 bits encode the operator's
|
||||||
|
// SyntaxKind value (e.g., PlusPlusToken=45, TildeToken=54), which fits because KindLastUnaryOperator (54) <= 0x3f (63).
|
||||||
|
//
|
||||||
|
// | Node type | Bits 0-5 | Notes |
|
||||||
|
// | ---------------------------- | ------------------------------------- | ------------------------------ |
|
||||||
|
// | `ImportSpecifier` | Bit 0: `isTypeOnly` | |
|
||||||
|
// | `ImportClause` | Bit 0: `isTypeOnly`, Bit 1: `isDefer` | |
|
||||||
|
// | `ExportSpecifier` | Bit 0: `isTypeOnly` | |
|
||||||
|
// | `ImportEqualsDeclaration` | Bit 0: `isTypeOnly` | |
|
||||||
|
// | `ExportDeclaration` | Bit 0: `isTypeOnly` | |
|
||||||
|
// | `ImportTypeNode` | Bit 0: `isTypeOf` | |
|
||||||
|
// | `ExportAssignment` | Bit 0: `isExportEquals` | |
|
||||||
|
// | `Block` | Bit 0: `multiline` | |
|
||||||
|
// | `ArrayLiteralExpression` | Bit 0: `multiline` | |
|
||||||
|
// | `ObjectLiteralExpression` | Bit 0: `multiline` | |
|
||||||
|
// | `JsxText` | Bit 0: `containsOnlyTriviaWhiteSpaces`| |
|
||||||
|
// | `JSDocTypeLiteral` | Bit 0: `isArrayType` | |
|
||||||
|
// | `JsDocPropertyTag` | Bit 0: `isBracketed`, Bit 1: `isNameFirst` | |
|
||||||
|
// | `JsDocParameterTag` | Bit 0: `isBracketed`, Bit 1: `isNameFirst` | |
|
||||||
|
// | `VariableDeclarationList` | Bit 0: is `let`, Bit 1: is `const` | |
|
||||||
|
// | `ImportAttributes` | Bit 0: `multiline`, Bit 1: is `assert`| |
|
||||||
|
// | `PrefixUnaryExpression` | Bits 0-5: operator SyntaxKind | e.g., `!`, `~`, `++`, `--` |
|
||||||
|
// | `PostfixUnaryExpression` | Bits 0-5: operator SyntaxKind | e.g., `++`, `--` |
|
||||||
|
//
|
||||||
|
// The remaining 3 bytes of the node data field vary by data type:
|
||||||
|
//
|
||||||
|
// ### Children (0b00)
|
||||||
|
//
|
||||||
|
// If a node has fewer children than its type allows, additional data is needed to determine which properties the children
|
||||||
|
// correspond to. The last byte of the 4-byte data field is a bitmask representing the child properties of the node type,
|
||||||
|
// in visitor order, where `1` indicates that the child at that property is present and `0` indicates that the property is
|
||||||
|
// nil. For example, a `MethodDeclaration` has the following child properties:
|
||||||
|
//
|
||||||
|
// | Property name | Bit position |
|
||||||
|
// | -------------- | ------------ |
|
||||||
|
// | modifiers | 0 |
|
||||||
|
// | asteriskToken | 1 |
|
||||||
|
// | name | 2 |
|
||||||
|
// | postfixToken | 3 |
|
||||||
|
// | typeParameters | 4 |
|
||||||
|
// | parameters | 5 |
|
||||||
|
// | returnType | 6 |
|
||||||
|
// | body | 7 |
|
||||||
|
//
|
||||||
|
// A bitmask with value `0b01100101` would indicate that the next four direct descendants (i.e., node records that have a
|
||||||
|
// `parent` set to the node index of the `MethodDeclaration`) of the node are its `modifiers`, `name`, `parameters`, and
|
||||||
|
// `body` properties, in that order. The remaining properties are nil. (To reconstruct the node with named properties, the
|
||||||
|
// client must consult a static table of each node type's child property names.)
|
||||||
|
//
|
||||||
|
// The bitmask may be zero for node types that can only have a single child, since no disambiguation is needed.
|
||||||
|
// Additionally, the children data type may be used for nodes that can never have children, but do not require other
|
||||||
|
// data types.
|
||||||
|
//
|
||||||
|
// ### String (0b01)
|
||||||
|
//
|
||||||
|
// The string data type is used for nodes with a single string property. (Currently, the name of that property is always
|
||||||
|
// `text`.) The last three bytes of the 4-byte data field form a single 24-bit unsigned integer (i.e.,
|
||||||
|
// `uint32(0x00_ff_ff_ff & node.data)`) _N_ that is an index into the **string offsets** section. The *N*th 32-bit
|
||||||
|
// unsigned integer in the **string offsets** section is the byte offset of the start of the string in the **string data**
|
||||||
|
// section, and the *N+1*th 32-bit unsigned integer is the byte offset of the end of the string in the
|
||||||
|
// **string data** section.
|
||||||
|
//
|
||||||
|
// ### Extended (0b10)
|
||||||
|
//
|
||||||
|
// The extended data type is used for nodes with properties that don't fit into either the children or string data types.
|
||||||
|
// The last three bytes of the 4-byte data field form a single 24-bit unsigned integer (i.e.,
|
||||||
|
// `uint32(0x00_ff_ff_ff & node.data)`) _N_ that is a byte offset into the **extended node data** section. The length and
|
||||||
|
// meaning of the data at that offset is defined by the node type. See the **Extended node data** section for details on
|
||||||
|
// the format of the extended data for specific node types.
|
||||||
|
//
|
||||||
|
// Encoding Arbitrary Nodes
|
||||||
|
// ------------------------
|
||||||
|
//
|
||||||
|
// The same binary format can be used to encode an arbitrary subtree of a SourceFile, not just a whole SourceFile. When
|
||||||
|
// encoding a non-SourceFile node, the format is identical with the following differences:
|
||||||
|
//
|
||||||
|
// - The content hash fields in the header (bytes 4-19) are zero.
|
||||||
|
// - The parse options field in the header (bytes 20-23) is zero.
|
||||||
|
// - The root node in the nodes section uses its actual node kind and data encoding (via getNodeData) rather than the
|
||||||
|
// SourceFile-specific extended data format.
|
||||||
|
//
|
||||||
|
// The string data section contains only the strings referenced by nodes in the subtree, rather than the full source
|
||||||
|
// file text. The EncodeNode function provides this entrypoint.
|
||||||
|
|
||||||
|
// SourceFileHash returns the 128-bit content hash for a source file as a hex string.
|
||||||
|
func SourceFileHash(sourceFile *ast.SourceFile) string {
|
||||||
|
h := sourceFile.Hash
|
||||||
|
return fmt.Sprintf("%016x%016x", h.Hi, h.Lo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeParseOptions encodes the per-file ExternalModuleIndicatorOptions as a uint32 bitmask.
|
||||||
|
func encodeParseOptions(opts ast.ExternalModuleIndicatorOptions) uint32 {
|
||||||
|
var bits uint32
|
||||||
|
if opts.JSX {
|
||||||
|
bits |= 1
|
||||||
|
}
|
||||||
|
if opts.Force {
|
||||||
|
bits |= 2
|
||||||
|
}
|
||||||
|
return bits
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeIndexTable maps between AST nodes and their encoder indices for O(1) node handle resolution.
|
||||||
|
type NodeIndexTable struct {
|
||||||
|
Nodes []*ast.Node // index → node (for resolution)
|
||||||
|
sortedOnce sync.Once
|
||||||
|
sortedIdx []uint32 // indices into Nodes, sorted by node ID; built lazily
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeIndexTableKey = ast.NewSourceFileDataKey[*NodeIndexTable]()
|
||||||
|
|
||||||
|
// GetIndex returns the encoder index for the given node.
|
||||||
|
// On the first call the sortedIdx array is built (O(n log n) sort on a flat []uint32),
|
||||||
|
// then subsequent calls use binary search (O(log n)). This turns out to be much faster than
|
||||||
|
// building a map[*ast.Node]uint32 and not significantly slower for lookups.
|
||||||
|
func (t *NodeIndexTable) GetIndex(node *ast.Node) uint32 {
|
||||||
|
t.sortedOnce.Do(func() {
|
||||||
|
idx := make([]uint32, 0, len(t.Nodes))
|
||||||
|
for i, n := range t.Nodes {
|
||||||
|
if n != nil {
|
||||||
|
idx = append(idx, uint32(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodes := t.Nodes
|
||||||
|
slices.SortFunc(idx, func(a, b uint32) int {
|
||||||
|
return cmp.Compare(ast.GetNodeId(nodes[a]), ast.GetNodeId(nodes[b]))
|
||||||
|
})
|
||||||
|
t.sortedIdx = idx
|
||||||
|
})
|
||||||
|
target := ast.GetNodeId(node)
|
||||||
|
i, found := core.BinarySearchUniqueFunc(t.sortedIdx, func(_ int, el uint32) int {
|
||||||
|
return cmp.Compare(ast.GetNodeId(t.Nodes[el]), target)
|
||||||
|
})
|
||||||
|
if found {
|
||||||
|
return t.sortedIdx[i]
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildNodeIndexTable walks the AST in the same order as encodeTree and builds
|
||||||
|
// a NodeIndexTable without performing the full binary encoding. This is used to
|
||||||
|
// eagerly create index tables for files that need node handles before getSourceFile
|
||||||
|
// is called. The indices produced are guaranteed to match those from EncodeSourceFile.
|
||||||
|
func BuildNodeIndexTable(sourceFile *ast.SourceFile) *NodeIndexTable {
|
||||||
|
var nodeCount uint32
|
||||||
|
nodeTable := make([]*ast.Node, 1, sourceFile.NodeCount+1) // index 0 = nil sentinel
|
||||||
|
|
||||||
|
visitor := &ast.NodeVisitor{
|
||||||
|
Hooks: ast.NodeVisitorHooks{
|
||||||
|
VisitNodes: func(nodeList *ast.NodeList, visitor *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if nodeList == nil {
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
nodeCount++
|
||||||
|
nodeTable = append(nodeTable, nil) // NodeLists are not *ast.Node
|
||||||
|
visitor.VisitSlice(nodeList.Nodes)
|
||||||
|
return nodeList
|
||||||
|
},
|
||||||
|
VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList {
|
||||||
|
if modifiers != nil && len(modifiers.Nodes) > 0 {
|
||||||
|
visitor.Hooks.VisitNodes(&modifiers.NodeList, visitor)
|
||||||
|
}
|
||||||
|
return modifiers
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
visitor.Visit = func(node *ast.Node) *ast.Node {
|
||||||
|
nodeCount++
|
||||||
|
nodeTable = append(nodeTable, node)
|
||||||
|
visitor.VisitEachChild(node)
|
||||||
|
for _, jsdoc := range node.JSDoc(sourceFile) {
|
||||||
|
visitor.Visit(jsdoc)
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
rootNode := sourceFile.AsNode()
|
||||||
|
// Index 1 = root node (matches encodeTree)
|
||||||
|
nodeCount++
|
||||||
|
nodeTable = append(nodeTable, rootNode)
|
||||||
|
|
||||||
|
visitor.VisitEachChild(rootNode)
|
||||||
|
for _, jsdoc := range rootNode.JSDoc(sourceFile) {
|
||||||
|
visitor.Visit(jsdoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &NodeIndexTable{Nodes: nodeTable}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNodeIndexTable(sourceFile *ast.SourceFile) *NodeIndexTable {
|
||||||
|
return ast.GetOrComputeSourceFileData(sourceFile, nodeIndexTableKey, BuildNodeIndexTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeSourceFile encodes an entire source file AST into the binary format.
|
||||||
|
// Returns the encoded bytes and a NodeIndexTable mapping encoder indices to AST nodes.
|
||||||
|
func EncodeSourceFile(sourceFile *ast.SourceFile) ([]byte, *NodeIndexTable, error) {
|
||||||
|
data, nodeTable, err := encodeTree(sourceFile.AsNode(), sourceFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
nodeTable = ast.GetOrComputeSourceFileData(sourceFile, nodeIndexTableKey, func(*ast.SourceFile) *NodeIndexTable {
|
||||||
|
return nodeTable
|
||||||
|
})
|
||||||
|
return data, nodeTable, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeNode encodes an arbitrary AST node and its descendants into the binary format.
|
||||||
|
// The sourceFile is needed to provide the source text for efficient string encoding.
|
||||||
|
// When encoding a non-SourceFile node, the header hash and parse options fields will be zero.
|
||||||
|
// Returns the encoded bytes and a NodeIndexTable mapping encoder indices to AST nodes.
|
||||||
|
func EncodeNode(node *ast.Node, sourceFile *ast.SourceFile) ([]byte, *NodeIndexTable, error) {
|
||||||
|
return encodeTree(node, sourceFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeTree(rootNode *ast.Node, sourceFile *ast.SourceFile) ([]byte, *NodeIndexTable, error) {
|
||||||
|
var parentIndex, nodeCount, prevIndex uint32
|
||||||
|
var extendedData []byte
|
||||||
|
var structuredData []byte
|
||||||
|
var strs *stringTable
|
||||||
|
var positionMap *ast.PositionMap
|
||||||
|
if rootNode.Kind == ast.KindSourceFile {
|
||||||
|
strs = newStringTable(sourceFile.Text(), sourceFile.TextCount)
|
||||||
|
positionMap = sourceFile.GetPositionMap()
|
||||||
|
} else {
|
||||||
|
strs = newStringTable("", 0)
|
||||||
|
if sourceFile != nil {
|
||||||
|
positionMap = sourceFile.GetPositionMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if positionMap == nil {
|
||||||
|
positionMap = ast.ComputePositionMap("")
|
||||||
|
}
|
||||||
|
utf16 := func(pos int) uint32 {
|
||||||
|
return uint32(positionMap.UTF8ToUTF16(pos))
|
||||||
|
}
|
||||||
|
var initialNodeCount int
|
||||||
|
if sourceFile != nil {
|
||||||
|
initialNodeCount = sourceFile.NodeCount
|
||||||
|
}
|
||||||
|
nodes := make([]byte, 0, (initialNodeCount+1)*NodeSize)
|
||||||
|
|
||||||
|
// Build node index table for O(1) handle resolution.
|
||||||
|
// Index 0 is a nil sentinel; real nodes start at index 1.
|
||||||
|
nodeTable := make([]*ast.Node, 1, initialNodeCount+1) // index 0 = nil sentinel
|
||||||
|
|
||||||
|
// Build a small map of nodes we need to track indices for (imports + moduleAugmentations).
|
||||||
|
// Values start at 0 and are filled in during the walk.
|
||||||
|
var nodeIndexMap map[*ast.Node]uint32
|
||||||
|
var sfExtendedDataOffset int // byte offset in extendedData where SourceFile fields start
|
||||||
|
if rootNode.Kind == ast.KindSourceFile {
|
||||||
|
sf := rootNode.AsSourceFile()
|
||||||
|
total := len(sf.Imports()) + len(sf.ModuleAugmentations)
|
||||||
|
if sf.ExternalModuleIndicator != nil && sf.ExternalModuleIndicator != rootNode {
|
||||||
|
total++
|
||||||
|
}
|
||||||
|
if total > 0 {
|
||||||
|
nodeIndexMap = make(map[*ast.Node]uint32, total)
|
||||||
|
for _, imp := range sf.Imports() {
|
||||||
|
nodeIndexMap[imp.AsNode()] = 0
|
||||||
|
}
|
||||||
|
for _, aug := range sf.ModuleAugmentations {
|
||||||
|
nodeIndexMap[aug.AsNode()] = 0
|
||||||
|
}
|
||||||
|
if sf.ExternalModuleIndicator != nil && sf.ExternalModuleIndicator != rootNode {
|
||||||
|
nodeIndexMap[sf.ExternalModuleIndicator] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor := &ast.NodeVisitor{
|
||||||
|
Hooks: ast.NodeVisitorHooks{
|
||||||
|
VisitNodes: func(nodeList *ast.NodeList, visitor *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if nodeList == nil {
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeCount++
|
||||||
|
nodeTable = append(nodeTable, nil) // NodeLists are not *ast.Node
|
||||||
|
if prevIndex != 0 {
|
||||||
|
// this is the next sibling of `prevNode`
|
||||||
|
b0, b1, b2, b3 := uint8(nodeCount), uint8(nodeCount>>8), uint8(nodeCount>>16), uint8(nodeCount>>24)
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+0] = b0
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+1] = b1
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+2] = b2
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+3] = b3
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = appendUint32s(nodes, SyntaxKindNodeList, utf16(nodeList.Pos()), utf16(nodeList.End()), 0, parentIndex, uint32(len(nodeList.Nodes)), 0)
|
||||||
|
|
||||||
|
saveParentIndex := parentIndex
|
||||||
|
|
||||||
|
currentIndex := nodeCount
|
||||||
|
prevIndex = 0
|
||||||
|
parentIndex = currentIndex
|
||||||
|
visitor.VisitSlice(nodeList.Nodes)
|
||||||
|
prevIndex = currentIndex
|
||||||
|
parentIndex = saveParentIndex
|
||||||
|
|
||||||
|
return nodeList
|
||||||
|
},
|
||||||
|
VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList {
|
||||||
|
if modifiers != nil && len(modifiers.Nodes) > 0 {
|
||||||
|
visitor.Hooks.VisitNodes(&modifiers.NodeList, visitor)
|
||||||
|
}
|
||||||
|
return modifiers
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
visitor.Visit = func(node *ast.Node) *ast.Node {
|
||||||
|
nodeCount++
|
||||||
|
nodeTable = append(nodeTable, node)
|
||||||
|
if prevIndex != 0 {
|
||||||
|
// this is the next sibling of `prevNode`
|
||||||
|
b0, b1, b2, b3 := uint8(nodeCount), uint8(nodeCount>>8), uint8(nodeCount>>16), uint8(nodeCount>>24)
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+0] = b0
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+1] = b1
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+2] = b2
|
||||||
|
nodes[prevIndex*NodeSize+NodeOffsetNext+3] = b3
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = appendUint32s(nodes, uint32(node.Kind), utf16(node.Pos()), utf16(node.End()), 0, parentIndex, getNodeData(node, strs, positionMap, &extendedData, &structuredData), uint32(node.Flags))
|
||||||
|
|
||||||
|
if nodeIndexMap != nil {
|
||||||
|
if _, ok := nodeIndexMap[node]; ok {
|
||||||
|
nodeIndexMap[node] = nodeCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveParentIndex := parentIndex
|
||||||
|
|
||||||
|
currentIndex := nodeCount
|
||||||
|
prevIndex = 0
|
||||||
|
parentIndex = currentIndex
|
||||||
|
visitor.VisitEachChild(node)
|
||||||
|
if sourceFile != nil {
|
||||||
|
for _, jsdoc := range node.JSDoc(sourceFile) {
|
||||||
|
visitor.Visit(jsdoc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevIndex = currentIndex
|
||||||
|
parentIndex = saveParentIndex
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = appendUint32s(nodes, 0, 0, 0, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
nodeCount++
|
||||||
|
parentIndex++
|
||||||
|
nodeTable = append(nodeTable, rootNode) // index 1 = root node
|
||||||
|
|
||||||
|
sfExtendedDataOffset = len(extendedData)
|
||||||
|
nodes = appendUint32s(nodes, uint32(rootNode.Kind), utf16(rootNode.Pos()), utf16(rootNode.End()), 0, 0, getNodeData(rootNode, strs, positionMap, &extendedData, &structuredData), uint32(rootNode.Flags))
|
||||||
|
|
||||||
|
visitor.VisitEachChild(rootNode)
|
||||||
|
if sourceFile != nil {
|
||||||
|
for _, jsdoc := range rootNode.JSDoc(sourceFile) {
|
||||||
|
visitor.Visit(jsdoc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash xxh3.Uint128
|
||||||
|
var parseOpts uint32
|
||||||
|
if rootNode.Kind == ast.KindSourceFile {
|
||||||
|
hash = sourceFile.Hash
|
||||||
|
parseOpts = encodeParseOptions(sourceFile.ParseOptions().ExternalModuleIndicatorOptions)
|
||||||
|
|
||||||
|
// Encode imports, moduleAugmentations, and ambientModuleNames into structured data,
|
||||||
|
// and patch the placeholder offsets in the SourceFile extended data.
|
||||||
|
sf := rootNode.AsSourceFile()
|
||||||
|
importsOffset := encodeNodeIndexArray(sf.Imports(), nodeIndexMap, &structuredData)
|
||||||
|
moduleAugmentationsOffset := encodeModuleAugmentations(sf.ModuleAugmentations, nodeIndexMap, &structuredData)
|
||||||
|
ambientModuleNamesOffset := encodeStringArray(sf.AmbientModuleNames, &structuredData)
|
||||||
|
// Patch the 3 placeholder uint32s at sfExtendedDataOffset + 32, 36, 40
|
||||||
|
binary.LittleEndian.PutUint32(extendedData[sfExtendedDataOffset+32:], importsOffset)
|
||||||
|
binary.LittleEndian.PutUint32(extendedData[sfExtendedDataOffset+36:], moduleAugmentationsOffset)
|
||||||
|
binary.LittleEndian.PutUint32(extendedData[sfExtendedDataOffset+40:], ambientModuleNamesOffset)
|
||||||
|
// Patch externalModuleIndicator node index at offset 44
|
||||||
|
var externalModuleIndicatorIndex uint32
|
||||||
|
if sf.ExternalModuleIndicator != nil {
|
||||||
|
if sf.ExternalModuleIndicator == rootNode {
|
||||||
|
externalModuleIndicatorIndex = 1 // root node index
|
||||||
|
} else {
|
||||||
|
externalModuleIndicatorIndex = nodeIndexMap[sf.ExternalModuleIndicator]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binary.LittleEndian.PutUint32(extendedData[sfExtendedDataOffset+44:], externalModuleIndicatorIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata := uint32(ProtocolVersion) << 24
|
||||||
|
offsetStringTableOffsets := HeaderSize
|
||||||
|
offsetStringTableData := HeaderSize + len(strs.offsets)*4
|
||||||
|
offsetExtendedData := offsetStringTableData + strs.stringLength()
|
||||||
|
offsetStructuredData := offsetExtendedData + len(extendedData)
|
||||||
|
offsetNodes := offsetStructuredData + len(structuredData)
|
||||||
|
|
||||||
|
header := []uint32{
|
||||||
|
metadata,
|
||||||
|
uint32(hash.Lo), uint32(hash.Lo >> 32),
|
||||||
|
uint32(hash.Hi), uint32(hash.Hi >> 32),
|
||||||
|
parseOpts,
|
||||||
|
uint32(offsetStringTableOffsets),
|
||||||
|
uint32(offsetStringTableData),
|
||||||
|
uint32(offsetExtendedData),
|
||||||
|
uint32(offsetStructuredData),
|
||||||
|
uint32(offsetNodes),
|
||||||
|
}
|
||||||
|
|
||||||
|
var headerBytes, strsBytes []byte
|
||||||
|
headerBytes = appendUint32s(nil, header...)
|
||||||
|
strsBytes = strs.encode()
|
||||||
|
|
||||||
|
return slices.Concat(
|
||||||
|
headerBytes,
|
||||||
|
strsBytes,
|
||||||
|
extendedData,
|
||||||
|
structuredData,
|
||||||
|
nodes,
|
||||||
|
), &NodeIndexTable{Nodes: nodeTable}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUint32s(buf []byte, values ...uint32) []byte {
|
||||||
|
for _, value := range values {
|
||||||
|
buf = binary.LittleEndian.AppendUint32(buf, value)
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNodeData(node *ast.Node, strs *stringTable, positionMap *ast.PositionMap, extendedData *[]byte, structuredData *[]byte) uint32 {
|
||||||
|
t := getNodeDataType(node)
|
||||||
|
switch t {
|
||||||
|
case NodeDataTypeChildren:
|
||||||
|
return t | getNodeCommonData(node) | uint32(getChildrenPropertyMask(node))
|
||||||
|
case NodeDataTypeString:
|
||||||
|
return t | getNodeCommonData(node) | recordNodeStrings(node, strs)
|
||||||
|
case NodeDataTypeExtendedData:
|
||||||
|
return t | getNodeCommonData(node) | recordExtendedData(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const noStructuredData = 0xFFFFFFFF
|
||||||
|
|
||||||
|
func recordExtendedData_SourceFile(node *ast.Node, strs *stringTable, positionMap *ast.PositionMap, extendedData *[]byte, structuredData *[]byte) {
|
||||||
|
sf := node.AsSourceFile()
|
||||||
|
textIndex := strs.add(sf.Text(), sf.Kind, sf.Pos(), sf.End())
|
||||||
|
fileNameIndex := strs.add(sf.FileName(), 0, 0, 0)
|
||||||
|
pathIndex := strs.add(string(sf.Path()), 0, 0, 0)
|
||||||
|
referencedFilesOffset := encodeFileReferences(sf.ReferencedFiles, positionMap, structuredData)
|
||||||
|
typeRefDirectivesOffset := encodeFileReferences(sf.TypeReferenceDirectives, positionMap, structuredData)
|
||||||
|
libRefDirectivesOffset := encodeFileReferences(sf.LibReferenceDirectives, positionMap, structuredData)
|
||||||
|
// imports, moduleAugmentations, ambientModuleNames offsets are placeholders;
|
||||||
|
// they will be patched after the tree walk when node indices are known.
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, fileNameIndex, pathIndex, uint32(sf.LanguageVariant), uint32(sf.ScriptKind), referencedFilesOffset, typeRefDirectivesOffset, libRefDirectivesOffset, noStructuredData, noStructuredData, noStructuredData, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_TemplateHead(node *ast.Node, strs *stringTable, positionMap *ast.PositionMap, extendedData *[]byte, structuredData *[]byte) {
|
||||||
|
n := node.AsTemplateHead()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
rawTextIndex := strs.add(n.RawText, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, rawTextIndex, uint32(n.TemplateFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_TemplateMiddle(node *ast.Node, strs *stringTable, positionMap *ast.PositionMap, extendedData *[]byte, structuredData *[]byte) {
|
||||||
|
n := node.AsTemplateMiddle()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
rawTextIndex := strs.add(n.RawText, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, rawTextIndex, uint32(n.TemplateFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_TemplateTail(node *ast.Node, strs *stringTable, positionMap *ast.PositionMap, extendedData *[]byte, structuredData *[]byte) {
|
||||||
|
n := node.AsTemplateTail()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
rawTextIndex := strs.add(n.RawText, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, rawTextIndex, uint32(n.TemplateFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolToByte(b bool) byte {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasModifiers returns true if the modifier list is non-nil and has at least one modifier.
|
||||||
|
func hasModifiers(modifiers *ast.ModifierList) bool {
|
||||||
|
return modifiers != nil && len(modifiers.Nodes) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeFileReferences encodes a slice of FileReferences as a msgpack array of tuples
|
||||||
|
// into the structured data buffer. Returns the byte offset into the buffer, or
|
||||||
|
// noStructuredData (0xFFFFFFFF) if the slice is empty.
|
||||||
|
func encodeFileReferences(refs []*ast.FileReference, positionMap *ast.PositionMap, buf *[]byte) uint32 {
|
||||||
|
if len(refs) == 0 {
|
||||||
|
return noStructuredData
|
||||||
|
}
|
||||||
|
offset := uint32(len(*buf))
|
||||||
|
*buf = msgpackWriteArrayHeader(*buf, len(refs))
|
||||||
|
for _, ref := range refs {
|
||||||
|
// Each entry is a 5-element tuple: [pos, end, fileName, resolutionMode, preserve]
|
||||||
|
*buf = msgpackWriteArrayHeader(*buf, 5)
|
||||||
|
*buf = msgpackWriteUint(*buf, uint32(positionMap.UTF8ToUTF16(ref.Pos())))
|
||||||
|
*buf = msgpackWriteUint(*buf, uint32(positionMap.UTF8ToUTF16(ref.End())))
|
||||||
|
*buf = msgpackWriteString(*buf, ref.FileName)
|
||||||
|
*buf = msgpackWriteUint(*buf, uint32(ref.ResolutionMode))
|
||||||
|
*buf = msgpackWriteBool(*buf, ref.Preserve)
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeNodeIndexArray encodes a slice of LiteralLikeNodes as a msgpack array of
|
||||||
|
// uint node indices. Returns the byte offset into the buffer, or noStructuredData
|
||||||
|
// if the slice is empty.
|
||||||
|
func encodeNodeIndexArray(nodes []*ast.LiteralLikeNode, indexMap map[*ast.Node]uint32, buf *[]byte) uint32 {
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return noStructuredData
|
||||||
|
}
|
||||||
|
offset := uint32(len(*buf))
|
||||||
|
*buf = msgpackWriteArrayHeader(*buf, len(nodes))
|
||||||
|
for _, node := range nodes {
|
||||||
|
*buf = msgpackWriteUint(*buf, indexMap[node.AsNode()])
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeModuleAugmentations encodes a slice of ModuleName nodes as a msgpack array
|
||||||
|
// of uint node indices. Returns the byte offset into the buffer, or noStructuredData
|
||||||
|
// if the slice is empty.
|
||||||
|
func encodeModuleAugmentations(nodes []*ast.ModuleName, indexMap map[*ast.Node]uint32, buf *[]byte) uint32 {
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return noStructuredData
|
||||||
|
}
|
||||||
|
offset := uint32(len(*buf))
|
||||||
|
*buf = msgpackWriteArrayHeader(*buf, len(nodes))
|
||||||
|
for _, node := range nodes {
|
||||||
|
*buf = msgpackWriteUint(*buf, indexMap[node.AsNode()])
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeStringArray encodes a slice of strings as a msgpack array of strings.
|
||||||
|
// Returns the byte offset into the buffer, or noStructuredData if the slice is empty.
|
||||||
|
func encodeStringArray(strs []string, buf *[]byte) uint32 {
|
||||||
|
if len(strs) == 0 {
|
||||||
|
return noStructuredData
|
||||||
|
}
|
||||||
|
offset := uint32(len(*buf))
|
||||||
|
*buf = msgpackWriteArrayHeader(*buf, len(strs))
|
||||||
|
for _, s := range strs {
|
||||||
|
*buf = msgpackWriteString(*buf, s)
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimal msgpack writers for the structured data section.
|
||||||
|
|
||||||
|
func msgpackWriteArrayHeader(buf []byte, length int) []byte {
|
||||||
|
if length <= 0x0f {
|
||||||
|
return append(buf, byte(0x90|length))
|
||||||
|
}
|
||||||
|
if length <= 0xffff {
|
||||||
|
return append(buf, 0xdc, byte(length>>8), byte(length))
|
||||||
|
}
|
||||||
|
return append(buf, 0xdd, byte(length>>24), byte(length>>16), byte(length>>8), byte(length))
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgpackWriteUint(buf []byte, value uint32) []byte {
|
||||||
|
if value <= 0x7f {
|
||||||
|
return append(buf, byte(value))
|
||||||
|
}
|
||||||
|
if value <= 0xff {
|
||||||
|
return append(buf, 0xcc, byte(value))
|
||||||
|
}
|
||||||
|
if value <= 0xffff {
|
||||||
|
return append(buf, 0xcd, byte(value>>8), byte(value))
|
||||||
|
}
|
||||||
|
return append(buf, 0xce, byte(value>>24), byte(value>>16), byte(value>>8), byte(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgpackWriteString(buf []byte, s string) []byte {
|
||||||
|
n := len(s)
|
||||||
|
if n <= 0x1f {
|
||||||
|
buf = append(buf, byte(0xa0|n))
|
||||||
|
} else if n <= 0xff {
|
||||||
|
buf = append(buf, 0xd9, byte(n))
|
||||||
|
} else if n <= 0xffff {
|
||||||
|
buf = append(buf, 0xda, byte(n>>8), byte(n))
|
||||||
|
} else {
|
||||||
|
buf = append(buf, 0xdb, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
|
||||||
|
}
|
||||||
|
return append(buf, s...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgpackWriteBool(buf []byte, value bool) []byte {
|
||||||
|
if value {
|
||||||
|
return append(buf, 0xc3)
|
||||||
|
}
|
||||||
|
return append(buf, 0xc2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand-written commonData encoding functions for nodes whose non-bool data
|
||||||
|
// members cannot be automatically encoded by the generator. Each function
|
||||||
|
// packs relevant fields into the 6-bit commonData area (bits 24-29) of the
|
||||||
|
// 32-bit node data word.
|
||||||
|
|
||||||
|
func getNodeCommonData_SyntheticExpression(_ *ast.Node) uint32 {
|
||||||
|
// SyntheticExpression is an internal compiler node that is never part of a parsed AST.
|
||||||
|
// It should never be encoded.
|
||||||
|
panic("SyntheticExpression should never be encoded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand-written extended data encoding functions for literal nodes that were
|
||||||
|
// previously string-type but whose TokenFlags/TemplateFlags cannot fit in 6 bits.
|
||||||
|
|
||||||
|
func recordExtendedData_StringLiteral(node *ast.Node, strs *stringTable, _ *ast.PositionMap, extendedData *[]byte, _ *[]byte) {
|
||||||
|
n := node.AsStringLiteral()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, uint32(n.TokenFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_NumericLiteral(node *ast.Node, strs *stringTable, _ *ast.PositionMap, extendedData *[]byte, _ *[]byte) {
|
||||||
|
n := node.AsNumericLiteral()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, uint32(n.TokenFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_BigIntLiteral(node *ast.Node, strs *stringTable, _ *ast.PositionMap, extendedData *[]byte, _ *[]byte) {
|
||||||
|
n := node.AsBigIntLiteral()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, uint32(n.TokenFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_RegularExpressionLiteral(node *ast.Node, strs *stringTable, _ *ast.PositionMap, extendedData *[]byte, _ *[]byte) {
|
||||||
|
n := node.AsRegularExpressionLiteral()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, uint32(n.TokenFlags))
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData_NoSubstitutionTemplateLiteral(node *ast.Node, strs *stringTable, _ *ast.PositionMap, extendedData *[]byte, _ *[]byte) {
|
||||||
|
n := node.AsNoSubstitutionTemplateLiteral()
|
||||||
|
textIndex := strs.add(n.Text, node.Kind, node.Pos(), node.End())
|
||||||
|
*extendedData = appendUint32s(*extendedData, textIndex, uint32(n.TemplateFlags))
|
||||||
|
}
|
||||||
707
tools/tsgo/internal/api/encoder/encoder_generated.go
Normal file
707
tools/tsgo/internal/api/encoder/encoder_generated.go
Normal file
@@ -0,0 +1,707 @@
|
|||||||
|
// Code generated by _scripts/generate-encoder.ts. DO NOT EDIT.
|
||||||
|
|
||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getNodeDataType(node *ast.Node) uint32 {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindIdentifier,
|
||||||
|
ast.KindPrivateIdentifier,
|
||||||
|
ast.KindJsxText,
|
||||||
|
ast.KindJSDocText,
|
||||||
|
ast.KindJSDocLink,
|
||||||
|
ast.KindJSDocLinkPlain,
|
||||||
|
ast.KindJSDocLinkCode:
|
||||||
|
return NodeDataTypeString
|
||||||
|
case ast.KindStringLiteral,
|
||||||
|
ast.KindNumericLiteral,
|
||||||
|
ast.KindBigIntLiteral,
|
||||||
|
ast.KindRegularExpressionLiteral,
|
||||||
|
ast.KindNoSubstitutionTemplateLiteral,
|
||||||
|
ast.KindTemplateHead,
|
||||||
|
ast.KindTemplateMiddle,
|
||||||
|
ast.KindTemplateTail,
|
||||||
|
ast.KindSourceFile:
|
||||||
|
return NodeDataTypeExtendedData
|
||||||
|
default:
|
||||||
|
return NodeDataTypeChildren
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChildrenPropertyMask(node *ast.Node) uint8 {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindQualifiedName:
|
||||||
|
n := node.AsQualifiedName()
|
||||||
|
return (boolToByte(n.Left != nil) << 0) | (boolToByte(n.Right != nil) << 1)
|
||||||
|
case ast.KindComputedPropertyName:
|
||||||
|
n := node.AsComputedPropertyName()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindDecorator:
|
||||||
|
n := node.AsDecorator()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindIfStatement:
|
||||||
|
n := node.AsIfStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.ThenStatement != nil) << 1) | (boolToByte(n.ElseStatement != nil) << 2)
|
||||||
|
case ast.KindDoStatement:
|
||||||
|
n := node.AsDoStatement()
|
||||||
|
return (boolToByte(n.Statement != nil) << 0) | (boolToByte(n.Expression != nil) << 1)
|
||||||
|
case ast.KindWhileStatement:
|
||||||
|
n := node.AsWhileStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Statement != nil) << 1)
|
||||||
|
case ast.KindForStatement:
|
||||||
|
n := node.AsForStatement()
|
||||||
|
return (boolToByte(n.Initializer != nil) << 0) | (boolToByte(n.Condition != nil) << 1) | (boolToByte(n.Incrementor != nil) << 2) | (boolToByte(n.Statement != nil) << 3)
|
||||||
|
case ast.KindForInStatement, ast.KindForOfStatement:
|
||||||
|
n := node.AsForInOrOfStatement()
|
||||||
|
return (boolToByte(n.AwaitModifier != nil) << 0) | (boolToByte(n.Initializer != nil) << 1) | (boolToByte(n.Expression != nil) << 2) | (boolToByte(n.Statement != nil) << 3)
|
||||||
|
case ast.KindBreakStatement:
|
||||||
|
n := node.AsBreakStatement()
|
||||||
|
return (boolToByte(n.Label != nil) << 0)
|
||||||
|
case ast.KindContinueStatement:
|
||||||
|
n := node.AsContinueStatement()
|
||||||
|
return (boolToByte(n.Label != nil) << 0)
|
||||||
|
case ast.KindReturnStatement:
|
||||||
|
n := node.AsReturnStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindWithStatement:
|
||||||
|
n := node.AsWithStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Statement != nil) << 1)
|
||||||
|
case ast.KindSwitchStatement:
|
||||||
|
n := node.AsSwitchStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.CaseBlock != nil) << 1)
|
||||||
|
case ast.KindCaseBlock:
|
||||||
|
n := node.AsCaseBlock()
|
||||||
|
return (boolToByte(n.Clauses != nil) << 0)
|
||||||
|
case ast.KindCaseClause, ast.KindDefaultClause:
|
||||||
|
n := node.AsCaseOrDefaultClause()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Statements != nil) << 1)
|
||||||
|
case ast.KindThrowStatement:
|
||||||
|
n := node.AsThrowStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindTryStatement:
|
||||||
|
n := node.AsTryStatement()
|
||||||
|
return (boolToByte(n.TryBlock != nil) << 0) | (boolToByte(n.CatchClause != nil) << 1) | (boolToByte(n.FinallyBlock != nil) << 2)
|
||||||
|
case ast.KindCatchClause:
|
||||||
|
n := node.AsCatchClause()
|
||||||
|
return (boolToByte(n.VariableDeclaration != nil) << 0) | (boolToByte(n.Block != nil) << 1)
|
||||||
|
case ast.KindLabeledStatement:
|
||||||
|
n := node.AsLabeledStatement()
|
||||||
|
return (boolToByte(n.Label != nil) << 0) | (boolToByte(n.Statement != nil) << 1)
|
||||||
|
case ast.KindExpressionStatement:
|
||||||
|
n := node.AsExpressionStatement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindBlock:
|
||||||
|
n := node.AsBlock()
|
||||||
|
return (boolToByte(n.Statements != nil) << 0)
|
||||||
|
case ast.KindVariableStatement:
|
||||||
|
n := node.AsVariableStatement()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.DeclarationList != nil) << 1)
|
||||||
|
case ast.KindVariableDeclaration:
|
||||||
|
n := node.AsVariableDeclaration()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.ExclamationToken != nil) << 1) | (boolToByte(n.Type != nil) << 2) | (boolToByte(n.Initializer != nil) << 3)
|
||||||
|
case ast.KindVariableDeclarationList:
|
||||||
|
n := node.AsVariableDeclarationList()
|
||||||
|
return (boolToByte(n.Declarations != nil) << 0)
|
||||||
|
case ast.KindObjectBindingPattern, ast.KindArrayBindingPattern:
|
||||||
|
n := node.AsBindingPattern()
|
||||||
|
return (boolToByte(n.Elements != nil) << 0)
|
||||||
|
case ast.KindParameter:
|
||||||
|
n := node.AsParameterDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.DotDotDotToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.QuestionToken != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Initializer != nil) << 5)
|
||||||
|
case ast.KindBindingElement:
|
||||||
|
n := node.AsBindingElement()
|
||||||
|
return (boolToByte(n.DotDotDotToken != nil) << 0) | (boolToByte(n.PropertyName != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.Initializer != nil) << 3)
|
||||||
|
case ast.KindMissingDeclaration:
|
||||||
|
n := node.AsMissingDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0)
|
||||||
|
case ast.KindFunctionDeclaration:
|
||||||
|
n := node.AsFunctionDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.AsteriskToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.TypeParameters != nil) << 3) | (boolToByte(n.Parameters != nil) << 4) | (boolToByte(n.Type != nil) << 5) | (boolToByte(n.Body != nil) << 6)
|
||||||
|
case ast.KindClassDeclaration:
|
||||||
|
n := node.AsClassDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.HeritageClauses != nil) << 3) | (boolToByte(n.Members != nil) << 4)
|
||||||
|
case ast.KindClassExpression:
|
||||||
|
n := node.AsClassExpression()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.HeritageClauses != nil) << 3) | (boolToByte(n.Members != nil) << 4)
|
||||||
|
case ast.KindHeritageClause:
|
||||||
|
n := node.AsHeritageClause()
|
||||||
|
return (boolToByte(n.Types != nil) << 0)
|
||||||
|
case ast.KindInterfaceDeclaration:
|
||||||
|
n := node.AsInterfaceDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.HeritageClauses != nil) << 3) | (boolToByte(n.Members != nil) << 4)
|
||||||
|
case ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration:
|
||||||
|
n := node.AsTypeAliasDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Type != nil) << 3)
|
||||||
|
case ast.KindEnumMember:
|
||||||
|
n := node.AsEnumMember()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Initializer != nil) << 1)
|
||||||
|
case ast.KindEnumDeclaration:
|
||||||
|
n := node.AsEnumDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.Members != nil) << 2)
|
||||||
|
case ast.KindModuleBlock:
|
||||||
|
n := node.AsModuleBlock()
|
||||||
|
return (boolToByte(n.Statements != nil) << 0)
|
||||||
|
case ast.KindImportDeclaration, ast.KindJSImportDeclaration:
|
||||||
|
n := node.AsImportDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.ImportClause != nil) << 1) | (boolToByte(n.ModuleSpecifier != nil) << 2) | (boolToByte(n.Attributes != nil) << 3)
|
||||||
|
case ast.KindExternalModuleReference:
|
||||||
|
n := node.AsExternalModuleReference()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindNamespaceImport:
|
||||||
|
n := node.AsNamespaceImport()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindNamedImports:
|
||||||
|
n := node.AsNamedImports()
|
||||||
|
return (boolToByte(n.Elements != nil) << 0)
|
||||||
|
case ast.KindExportAssignment:
|
||||||
|
n := node.AsExportAssignment()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Type != nil) << 1) | (boolToByte(n.Expression != nil) << 2)
|
||||||
|
case ast.KindNamespaceExportDeclaration:
|
||||||
|
n := node.AsNamespaceExportDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1)
|
||||||
|
case ast.KindNamespaceExport:
|
||||||
|
n := node.AsNamespaceExport()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindNamedExports:
|
||||||
|
n := node.AsNamedExports()
|
||||||
|
return (boolToByte(n.Elements != nil) << 0)
|
||||||
|
case ast.KindExportSpecifier:
|
||||||
|
n := node.AsExportSpecifier()
|
||||||
|
return (boolToByte(n.PropertyName != nil) << 0) | (boolToByte(n.Name() != nil) << 1)
|
||||||
|
case ast.KindCallSignature:
|
||||||
|
n := node.AsCallSignatureDeclaration()
|
||||||
|
return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2)
|
||||||
|
case ast.KindConstructSignature:
|
||||||
|
n := node.AsConstructSignatureDeclaration()
|
||||||
|
return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2)
|
||||||
|
case ast.KindConstructor:
|
||||||
|
n := node.AsConstructorDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.TypeParameters != nil) << 1) | (boolToByte(n.Parameters != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Body != nil) << 4)
|
||||||
|
case ast.KindGetAccessor:
|
||||||
|
n := node.AsGetAccessorDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Parameters != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Body != nil) << 5)
|
||||||
|
case ast.KindSetAccessor:
|
||||||
|
n := node.AsSetAccessorDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Parameters != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Body != nil) << 5)
|
||||||
|
case ast.KindIndexSignature:
|
||||||
|
n := node.AsIndexSignatureDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2)
|
||||||
|
case ast.KindMethodSignature:
|
||||||
|
n := node.AsMethodSignatureDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.TypeParameters != nil) << 3) | (boolToByte(n.Parameters != nil) << 4) | (boolToByte(n.Type != nil) << 5)
|
||||||
|
case ast.KindMethodDeclaration:
|
||||||
|
n := node.AsMethodDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.AsteriskToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.PostfixToken != nil) << 3) | (boolToByte(n.TypeParameters != nil) << 4) | (boolToByte(n.Parameters != nil) << 5) | (boolToByte(n.Type != nil) << 6) | (boolToByte(n.Body != nil) << 7)
|
||||||
|
case ast.KindPropertySignature:
|
||||||
|
n := node.AsPropertySignatureDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Initializer != nil) << 4)
|
||||||
|
case ast.KindPropertyDeclaration:
|
||||||
|
n := node.AsPropertyDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Initializer != nil) << 4)
|
||||||
|
case ast.KindClassStaticBlockDeclaration:
|
||||||
|
n := node.AsClassStaticBlockDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Body != nil) << 1)
|
||||||
|
case ast.KindBinaryExpression:
|
||||||
|
n := node.AsBinaryExpression()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Left != nil) << 1) | (boolToByte(n.Type != nil) << 2) | (boolToByte(n.OperatorToken != nil) << 3) | (boolToByte(n.Right != nil) << 4)
|
||||||
|
case ast.KindPrefixUnaryExpression:
|
||||||
|
n := node.AsPrefixUnaryExpression()
|
||||||
|
return (boolToByte(n.Operand != nil) << 0)
|
||||||
|
case ast.KindPostfixUnaryExpression:
|
||||||
|
n := node.AsPostfixUnaryExpression()
|
||||||
|
return (boolToByte(n.Operand != nil) << 0)
|
||||||
|
case ast.KindYieldExpression:
|
||||||
|
n := node.AsYieldExpression()
|
||||||
|
return (boolToByte(n.AsteriskToken != nil) << 0) | (boolToByte(n.Expression != nil) << 1)
|
||||||
|
case ast.KindArrowFunction:
|
||||||
|
n := node.AsArrowFunction()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.TypeParameters != nil) << 1) | (boolToByte(n.Parameters != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.EqualsGreaterThanToken != nil) << 4) | (boolToByte(n.Body != nil) << 5)
|
||||||
|
case ast.KindFunctionExpression:
|
||||||
|
n := node.AsFunctionExpression()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.AsteriskToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.TypeParameters != nil) << 3) | (boolToByte(n.Parameters != nil) << 4) | (boolToByte(n.Type != nil) << 5) | (boolToByte(n.Body != nil) << 6)
|
||||||
|
case ast.KindAsExpression:
|
||||||
|
n := node.AsAsExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Type != nil) << 1)
|
||||||
|
case ast.KindSatisfiesExpression:
|
||||||
|
n := node.AsSatisfiesExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Type != nil) << 1)
|
||||||
|
case ast.KindConditionalExpression:
|
||||||
|
n := node.AsConditionalExpression()
|
||||||
|
return (boolToByte(n.Condition != nil) << 0) | (boolToByte(n.QuestionToken != nil) << 1) | (boolToByte(n.WhenTrue != nil) << 2) | (boolToByte(n.ColonToken != nil) << 3) | (boolToByte(n.WhenFalse != nil) << 4)
|
||||||
|
case ast.KindPropertyAccessExpression:
|
||||||
|
n := node.AsPropertyAccessExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2)
|
||||||
|
case ast.KindElementAccessExpression:
|
||||||
|
n := node.AsElementAccessExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.ArgumentExpression != nil) << 2)
|
||||||
|
case ast.KindCallExpression:
|
||||||
|
n := node.AsCallExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.TypeArguments != nil) << 2) | (boolToByte(n.Arguments != nil) << 3)
|
||||||
|
case ast.KindNewExpression:
|
||||||
|
n := node.AsNewExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) | (boolToByte(n.Arguments != nil) << 2)
|
||||||
|
case ast.KindMetaProperty:
|
||||||
|
n := node.AsMetaProperty()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindNonNullExpression:
|
||||||
|
n := node.AsNonNullExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindSpreadElement:
|
||||||
|
n := node.AsSpreadElement()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindTemplateExpression:
|
||||||
|
n := node.AsTemplateExpression()
|
||||||
|
return (boolToByte(n.Head != nil) << 0) | (boolToByte(n.TemplateSpans != nil) << 1)
|
||||||
|
case ast.KindTemplateSpan:
|
||||||
|
n := node.AsTemplateSpan()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Literal != nil) << 1)
|
||||||
|
case ast.KindTaggedTemplateExpression:
|
||||||
|
n := node.AsTaggedTemplateExpression()
|
||||||
|
return (boolToByte(n.Tag != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.TypeArguments != nil) << 2) | (boolToByte(n.Template != nil) << 3)
|
||||||
|
case ast.KindParenthesizedExpression:
|
||||||
|
n := node.AsParenthesizedExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindArrayLiteralExpression:
|
||||||
|
n := node.AsArrayLiteralExpression()
|
||||||
|
return (boolToByte(n.Elements != nil) << 0)
|
||||||
|
case ast.KindObjectLiteralExpression:
|
||||||
|
n := node.AsObjectLiteralExpression()
|
||||||
|
return (boolToByte(n.Properties != nil) << 0)
|
||||||
|
case ast.KindSpreadAssignment:
|
||||||
|
n := node.AsSpreadAssignment()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindPropertyAssignment:
|
||||||
|
n := node.AsPropertyAssignment()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Initializer != nil) << 4)
|
||||||
|
case ast.KindShorthandPropertyAssignment:
|
||||||
|
n := node.AsShorthandPropertyAssignment()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.EqualsToken != nil) << 4) | (boolToByte(n.ObjectAssignmentInitializer != nil) << 5)
|
||||||
|
case ast.KindDeleteExpression:
|
||||||
|
n := node.AsDeleteExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindTypeOfExpression:
|
||||||
|
n := node.AsTypeOfExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindVoidExpression:
|
||||||
|
n := node.AsVoidExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindAwaitExpression:
|
||||||
|
n := node.AsAwaitExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindTypeAssertionExpression:
|
||||||
|
n := node.AsTypeAssertion()
|
||||||
|
return (boolToByte(n.Type != nil) << 0) | (boolToByte(n.Expression != nil) << 1)
|
||||||
|
case ast.KindUnionType:
|
||||||
|
n := node.AsUnionTypeNode()
|
||||||
|
return (boolToByte(n.Types != nil) << 0)
|
||||||
|
case ast.KindIntersectionType:
|
||||||
|
n := node.AsIntersectionTypeNode()
|
||||||
|
return (boolToByte(n.Types != nil) << 0)
|
||||||
|
case ast.KindConditionalType:
|
||||||
|
n := node.AsConditionalTypeNode()
|
||||||
|
return (boolToByte(n.CheckType != nil) << 0) | (boolToByte(n.ExtendsType != nil) << 1) | (boolToByte(n.TrueType != nil) << 2) | (boolToByte(n.FalseType != nil) << 3)
|
||||||
|
case ast.KindTypeOperator:
|
||||||
|
n := node.AsTypeOperatorNode()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindInferType:
|
||||||
|
n := node.AsInferTypeNode()
|
||||||
|
return (boolToByte(n.TypeParameter != nil) << 0)
|
||||||
|
case ast.KindArrayType:
|
||||||
|
n := node.AsArrayTypeNode()
|
||||||
|
return (boolToByte(n.ElementType != nil) << 0)
|
||||||
|
case ast.KindIndexedAccessType:
|
||||||
|
n := node.AsIndexedAccessTypeNode()
|
||||||
|
return (boolToByte(n.ObjectType != nil) << 0) | (boolToByte(n.IndexType != nil) << 1)
|
||||||
|
case ast.KindTypeReference:
|
||||||
|
n := node.AsTypeReferenceNode()
|
||||||
|
return (boolToByte(n.TypeName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1)
|
||||||
|
case ast.KindExpressionWithTypeArguments:
|
||||||
|
n := node.AsExpressionWithTypeArguments()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1)
|
||||||
|
case ast.KindLiteralType:
|
||||||
|
n := node.AsLiteralTypeNode()
|
||||||
|
return (boolToByte(n.Literal != nil) << 0)
|
||||||
|
case ast.KindTypePredicate:
|
||||||
|
n := node.AsTypePredicateNode()
|
||||||
|
return (boolToByte(n.AssertsModifier != nil) << 0) | (boolToByte(n.ParameterName != nil) << 1) | (boolToByte(n.Type != nil) << 2)
|
||||||
|
case ast.KindImportAttribute:
|
||||||
|
n := node.AsImportAttribute()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Value != nil) << 1)
|
||||||
|
case ast.KindImportAttributes:
|
||||||
|
n := node.AsImportAttributes()
|
||||||
|
return (boolToByte(n.Attributes != nil) << 0)
|
||||||
|
case ast.KindTypeQuery:
|
||||||
|
n := node.AsTypeQueryNode()
|
||||||
|
return (boolToByte(n.ExprName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1)
|
||||||
|
case ast.KindMappedType:
|
||||||
|
n := node.AsMappedTypeNode()
|
||||||
|
return (boolToByte(n.ReadonlyToken != nil) << 0) | (boolToByte(n.TypeParameter != nil) << 1) | (boolToByte(n.NameType != nil) << 2) | (boolToByte(n.QuestionToken != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Members != nil) << 5)
|
||||||
|
case ast.KindTypeLiteral:
|
||||||
|
n := node.AsTypeLiteralNode()
|
||||||
|
return (boolToByte(n.Members != nil) << 0)
|
||||||
|
case ast.KindTupleType:
|
||||||
|
n := node.AsTupleTypeNode()
|
||||||
|
return (boolToByte(n.Elements != nil) << 0)
|
||||||
|
case ast.KindNamedTupleMember:
|
||||||
|
n := node.AsNamedTupleMember()
|
||||||
|
return (boolToByte(n.DotDotDotToken != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.QuestionToken != nil) << 2) | (boolToByte(n.Type != nil) << 3)
|
||||||
|
case ast.KindOptionalType:
|
||||||
|
n := node.AsOptionalTypeNode()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindRestType:
|
||||||
|
n := node.AsRestTypeNode()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindParenthesizedType:
|
||||||
|
n := node.AsParenthesizedTypeNode()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindFunctionType:
|
||||||
|
n := node.AsFunctionTypeNode()
|
||||||
|
return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2)
|
||||||
|
case ast.KindConstructorType:
|
||||||
|
n := node.AsConstructorTypeNode()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.TypeParameters != nil) << 1) | (boolToByte(n.Parameters != nil) << 2) | (boolToByte(n.Type != nil) << 3)
|
||||||
|
case ast.KindTemplateLiteralType:
|
||||||
|
n := node.AsTemplateLiteralTypeNode()
|
||||||
|
return (boolToByte(n.Head != nil) << 0) | (boolToByte(n.TemplateSpans != nil) << 1)
|
||||||
|
case ast.KindTemplateLiteralTypeSpan:
|
||||||
|
n := node.AsTemplateLiteralTypeSpan()
|
||||||
|
return (boolToByte(n.Type != nil) << 0) | (boolToByte(n.Literal != nil) << 1)
|
||||||
|
case ast.KindSyntheticExpression:
|
||||||
|
n := node.AsSyntheticExpression()
|
||||||
|
return (boolToByte(n.TupleNameSource != nil) << 0)
|
||||||
|
case ast.KindPartiallyEmittedExpression:
|
||||||
|
n := node.AsPartiallyEmittedExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindJsxElement:
|
||||||
|
n := node.AsJsxElement()
|
||||||
|
return (boolToByte(n.OpeningElement != nil) << 0) | (boolToByte(n.Children != nil) << 1) | (boolToByte(n.ClosingElement != nil) << 2)
|
||||||
|
case ast.KindJsxAttributes:
|
||||||
|
n := node.AsJsxAttributes()
|
||||||
|
return (boolToByte(n.Properties != nil) << 0)
|
||||||
|
case ast.KindJsxNamespacedName:
|
||||||
|
n := node.AsJsxNamespacedName()
|
||||||
|
return (boolToByte(n.Namespace != nil) << 0) | (boolToByte(n.Name() != nil) << 1)
|
||||||
|
case ast.KindJsxOpeningElement:
|
||||||
|
n := node.AsJsxOpeningElement()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) | (boolToByte(n.Attributes != nil) << 2)
|
||||||
|
case ast.KindJsxSelfClosingElement:
|
||||||
|
n := node.AsJsxSelfClosingElement()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) | (boolToByte(n.Attributes != nil) << 2)
|
||||||
|
case ast.KindJsxFragment:
|
||||||
|
n := node.AsJsxFragment()
|
||||||
|
return (boolToByte(n.OpeningFragment != nil) << 0) | (boolToByte(n.Children != nil) << 1) | (boolToByte(n.ClosingFragment != nil) << 2)
|
||||||
|
case ast.KindJsxAttribute:
|
||||||
|
n := node.AsJsxAttribute()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Initializer != nil) << 1)
|
||||||
|
case ast.KindJsxSpreadAttribute:
|
||||||
|
n := node.AsJsxSpreadAttribute()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0)
|
||||||
|
case ast.KindJsxClosingElement:
|
||||||
|
n := node.AsJsxClosingElement()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0)
|
||||||
|
case ast.KindJsxExpression:
|
||||||
|
n := node.AsJsxExpression()
|
||||||
|
return (boolToByte(n.DotDotDotToken != nil) << 0) | (boolToByte(n.Expression != nil) << 1)
|
||||||
|
case ast.KindSyntaxList:
|
||||||
|
n := node.AsSyntaxList()
|
||||||
|
return (boolToByte(len(n.Children) > 0) << 0)
|
||||||
|
case ast.KindJSDoc:
|
||||||
|
n := node.AsJSDoc()
|
||||||
|
return (boolToByte(n.Comment != nil) << 0) | (boolToByte(n.Tags != nil) << 1)
|
||||||
|
case ast.KindJSDocTypeExpression:
|
||||||
|
n := node.AsJSDocTypeExpression()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindJSDocNonNullableType:
|
||||||
|
n := node.AsJSDocNonNullableType()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindJSDocNullableType:
|
||||||
|
n := node.AsJSDocNullableType()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindJSDocVariadicType:
|
||||||
|
n := node.AsJSDocVariadicType()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindJSDocOptionalType:
|
||||||
|
n := node.AsJSDocOptionalType()
|
||||||
|
return (boolToByte(n.Type != nil) << 0)
|
||||||
|
case ast.KindJSDocTypeTag:
|
||||||
|
n := node.AsJSDocTypeTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocUnknownTag:
|
||||||
|
n := node.AsJSDocUnknownTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocTemplateTag:
|
||||||
|
n := node.AsJSDocTemplateTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Constraint != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Comment != nil) << 3)
|
||||||
|
case ast.KindJSDocReturnTag:
|
||||||
|
n := node.AsJSDocReturnTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocPublicTag:
|
||||||
|
n := node.AsJSDocPublicTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocPrivateTag:
|
||||||
|
n := node.AsJSDocPrivateTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocProtectedTag:
|
||||||
|
n := node.AsJSDocProtectedTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocReadonlyTag:
|
||||||
|
n := node.AsJSDocReadonlyTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocOverrideTag:
|
||||||
|
n := node.AsJSDocOverrideTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocDeprecatedTag:
|
||||||
|
n := node.AsJSDocDeprecatedTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1)
|
||||||
|
case ast.KindJSDocSeeTag:
|
||||||
|
n := node.AsJSDocSeeTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.NameExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocImplementsTag:
|
||||||
|
n := node.AsJSDocImplementsTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.ClassName != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocAugmentsTag:
|
||||||
|
n := node.AsJSDocAugmentsTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.ClassName != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocSatisfiesTag:
|
||||||
|
n := node.AsJSDocSatisfiesTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocThrowsTag:
|
||||||
|
n := node.AsJSDocThrowsTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocThisTag:
|
||||||
|
n := node.AsJSDocThisTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocImportTag:
|
||||||
|
n := node.AsJSDocImportTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.ImportClause != nil) << 1) | (boolToByte(n.ModuleSpecifier != nil) << 2) | (boolToByte(n.Attributes != nil) << 3) | (boolToByte(n.Comment != nil) << 4)
|
||||||
|
case ast.KindJSDocCallbackTag:
|
||||||
|
n := node.AsJSDocCallbackTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.Comment != nil) << 3)
|
||||||
|
case ast.KindJSDocOverloadTag:
|
||||||
|
n := node.AsJSDocOverloadTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2)
|
||||||
|
case ast.KindJSDocTypedefTag:
|
||||||
|
n := node.AsJSDocTypedefTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.Comment != nil) << 3)
|
||||||
|
case ast.KindJSDocSignature:
|
||||||
|
n := node.AsJSDocSignature()
|
||||||
|
return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2)
|
||||||
|
case ast.KindJSDocNameReference:
|
||||||
|
n := node.AsJSDocNameReference()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindModuleDeclaration:
|
||||||
|
n := node.AsModuleDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.Body != nil) << 2)
|
||||||
|
case ast.KindImportEqualsDeclaration:
|
||||||
|
n := node.AsImportEqualsDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.ModuleReference != nil) << 2)
|
||||||
|
case ast.KindExportDeclaration:
|
||||||
|
n := node.AsExportDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.ExportClause != nil) << 1) | (boolToByte(n.ModuleSpecifier != nil) << 2) | (boolToByte(n.Attributes != nil) << 3)
|
||||||
|
case ast.KindImportType:
|
||||||
|
n := node.AsImportTypeNode()
|
||||||
|
return (boolToByte(n.Argument != nil) << 0) | (boolToByte(n.Attributes != nil) << 1) | (boolToByte(n.Qualifier != nil) << 2) | (boolToByte(n.TypeArguments != nil) << 3)
|
||||||
|
case ast.KindImportClause:
|
||||||
|
n := node.AsImportClause()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.NamedBindings != nil) << 1)
|
||||||
|
case ast.KindImportSpecifier:
|
||||||
|
n := node.AsImportSpecifier()
|
||||||
|
return (boolToByte(n.PropertyName != nil) << 0) | (boolToByte(n.Name() != nil) << 1)
|
||||||
|
case ast.KindJSDocLink:
|
||||||
|
n := node.AsJSDocLink()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindJSDocLinkPlain:
|
||||||
|
n := node.AsJSDocLinkPlain()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindJSDocLinkCode:
|
||||||
|
n := node.AsJSDocLinkCode()
|
||||||
|
return (boolToByte(n.Name() != nil) << 0)
|
||||||
|
case ast.KindTypeParameter:
|
||||||
|
n := node.AsTypeParameterDeclaration()
|
||||||
|
return (boolToByte(hasModifiers(n.Modifiers())) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.Constraint != nil) << 2) | (boolToByte(n.Expression != nil) << 3) | (boolToByte(n.DefaultType != nil) << 4)
|
||||||
|
case ast.KindSyntheticReferenceExpression:
|
||||||
|
n := node.AsSyntheticReferenceExpression()
|
||||||
|
return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.ThisArg != nil) << 1)
|
||||||
|
case ast.KindJSDocTypeLiteral:
|
||||||
|
n := node.AsJSDocTypeLiteral()
|
||||||
|
return (boolToByte(len(n.JSDocPropertyTags) > 0) << 0)
|
||||||
|
case ast.KindJSDocParameterTag, ast.KindJSDocPropertyTag:
|
||||||
|
n := node.AsJSDocParameterOrPropertyTag()
|
||||||
|
return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeExpression != nil) << 2) | (boolToByte(n.Comment != nil) << 3)
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNodeCommonData(node *ast.Node) uint32 {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindBlock:
|
||||||
|
n := node.AsBlock()
|
||||||
|
return uint32(boolToByte(n.MultiLine)) << 24
|
||||||
|
case ast.KindHeritageClause:
|
||||||
|
n := node.AsHeritageClause()
|
||||||
|
var tokenIdx uint32
|
||||||
|
switch n.Token {
|
||||||
|
case ast.KindImplementsKeyword:
|
||||||
|
tokenIdx = 1
|
||||||
|
}
|
||||||
|
return tokenIdx << 24
|
||||||
|
case ast.KindExportAssignment:
|
||||||
|
n := node.AsExportAssignment()
|
||||||
|
return uint32(boolToByte(n.IsExportEquals)) << 24
|
||||||
|
case ast.KindExportSpecifier:
|
||||||
|
n := node.AsExportSpecifier()
|
||||||
|
return uint32(boolToByte(n.IsTypeOnly)) << 24
|
||||||
|
case ast.KindPrefixUnaryExpression:
|
||||||
|
n := node.AsPrefixUnaryExpression()
|
||||||
|
var operatorIdx uint32
|
||||||
|
switch n.Operator {
|
||||||
|
case ast.KindMinusToken:
|
||||||
|
operatorIdx = 1
|
||||||
|
case ast.KindTildeToken:
|
||||||
|
operatorIdx = 2
|
||||||
|
case ast.KindExclamationToken:
|
||||||
|
operatorIdx = 3
|
||||||
|
case ast.KindPlusPlusToken:
|
||||||
|
operatorIdx = 4
|
||||||
|
case ast.KindMinusMinusToken:
|
||||||
|
operatorIdx = 5
|
||||||
|
}
|
||||||
|
return operatorIdx << 24
|
||||||
|
case ast.KindPostfixUnaryExpression:
|
||||||
|
n := node.AsPostfixUnaryExpression()
|
||||||
|
var operatorIdx uint32
|
||||||
|
switch n.Operator {
|
||||||
|
case ast.KindMinusMinusToken:
|
||||||
|
operatorIdx = 1
|
||||||
|
}
|
||||||
|
return operatorIdx << 24
|
||||||
|
case ast.KindMetaProperty:
|
||||||
|
n := node.AsMetaProperty()
|
||||||
|
var keywordTokenIdx uint32
|
||||||
|
switch n.KeywordToken {
|
||||||
|
case ast.KindNewKeyword:
|
||||||
|
keywordTokenIdx = 1
|
||||||
|
}
|
||||||
|
return keywordTokenIdx << 24
|
||||||
|
case ast.KindArrayLiteralExpression:
|
||||||
|
n := node.AsArrayLiteralExpression()
|
||||||
|
return uint32(boolToByte(n.MultiLine)) << 24
|
||||||
|
case ast.KindObjectLiteralExpression:
|
||||||
|
n := node.AsObjectLiteralExpression()
|
||||||
|
return uint32(boolToByte(n.MultiLine)) << 24
|
||||||
|
case ast.KindTypeOperator:
|
||||||
|
n := node.AsTypeOperatorNode()
|
||||||
|
var operatorIdx uint32
|
||||||
|
switch n.Operator {
|
||||||
|
case ast.KindReadonlyKeyword:
|
||||||
|
operatorIdx = 1
|
||||||
|
case ast.KindUniqueKeyword:
|
||||||
|
operatorIdx = 2
|
||||||
|
}
|
||||||
|
return operatorIdx << 24
|
||||||
|
case ast.KindImportAttributes:
|
||||||
|
n := node.AsImportAttributes()
|
||||||
|
var tokenIdx uint32
|
||||||
|
switch n.Token {
|
||||||
|
case ast.KindAssertKeyword:
|
||||||
|
tokenIdx = 1
|
||||||
|
}
|
||||||
|
return uint32(boolToByte(n.MultiLine))<<24 | tokenIdx<<25
|
||||||
|
case ast.KindSyntheticExpression:
|
||||||
|
return getNodeCommonData_SyntheticExpression(node)
|
||||||
|
case ast.KindJsxText:
|
||||||
|
n := node.AsJsxText()
|
||||||
|
return uint32(boolToByte(n.ContainsOnlyTriviaWhiteSpaces)) << 24
|
||||||
|
case ast.KindModuleDeclaration:
|
||||||
|
n := node.AsModuleDeclaration()
|
||||||
|
var keywordIdx uint32
|
||||||
|
switch n.Keyword {
|
||||||
|
case ast.KindNamespaceKeyword:
|
||||||
|
keywordIdx = 1
|
||||||
|
}
|
||||||
|
return keywordIdx << 24
|
||||||
|
case ast.KindImportEqualsDeclaration:
|
||||||
|
n := node.AsImportEqualsDeclaration()
|
||||||
|
return uint32(boolToByte(n.IsTypeOnly)) << 24
|
||||||
|
case ast.KindExportDeclaration:
|
||||||
|
n := node.AsExportDeclaration()
|
||||||
|
return uint32(boolToByte(n.IsTypeOnly)) << 24
|
||||||
|
case ast.KindImportType:
|
||||||
|
n := node.AsImportTypeNode()
|
||||||
|
return uint32(boolToByte(n.IsTypeOf)) << 24
|
||||||
|
case ast.KindImportClause:
|
||||||
|
n := node.AsImportClause()
|
||||||
|
var phaseModifierIdx uint32
|
||||||
|
switch n.PhaseModifier {
|
||||||
|
case ast.KindTypeKeyword:
|
||||||
|
phaseModifierIdx = 1
|
||||||
|
case ast.KindDeferKeyword:
|
||||||
|
phaseModifierIdx = 2
|
||||||
|
}
|
||||||
|
return phaseModifierIdx << 24
|
||||||
|
case ast.KindImportSpecifier:
|
||||||
|
n := node.AsImportSpecifier()
|
||||||
|
return uint32(boolToByte(n.IsTypeOnly)) << 24
|
||||||
|
case ast.KindJSDocTypeLiteral:
|
||||||
|
n := node.AsJSDocTypeLiteral()
|
||||||
|
return uint32(boolToByte(n.IsArrayType)) << 24
|
||||||
|
case ast.KindJSDocParameterTag, ast.KindJSDocPropertyTag:
|
||||||
|
n := node.AsJSDocParameterOrPropertyTag()
|
||||||
|
return uint32(boolToByte(n.IsBracketed))<<24 | uint32(boolToByte(n.IsNameFirst))<<25
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordNodeStrings(node *ast.Node, strs *stringTable) uint32 {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindIdentifier:
|
||||||
|
return strs.add(node.AsIdentifier().Text, node.Kind, node.Pos(), node.End())
|
||||||
|
case ast.KindPrivateIdentifier:
|
||||||
|
return strs.add(node.AsPrivateIdentifier().Text, node.Kind, node.Pos(), node.End())
|
||||||
|
case ast.KindJsxText:
|
||||||
|
return strs.add(node.AsJsxText().Text, node.Kind, node.Pos(), node.End())
|
||||||
|
case ast.KindJSDocText:
|
||||||
|
return strs.add(node.AsJSDocText().Text(), node.Kind, node.Pos(), node.End())
|
||||||
|
case ast.KindJSDocLink:
|
||||||
|
return strs.add(node.AsJSDocLink().Text(), node.Kind, node.Pos(), node.End())
|
||||||
|
case ast.KindJSDocLinkPlain:
|
||||||
|
return strs.add(node.AsJSDocLinkPlain().Text(), node.Kind, node.Pos(), node.End())
|
||||||
|
case ast.KindJSDocLinkCode:
|
||||||
|
return strs.add(node.AsJSDocLinkCode().Text(), node.Kind, node.Pos(), node.End())
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Unexpected node kind %v", node.Kind))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordExtendedData(node *ast.Node, strs *stringTable, positionMap *ast.PositionMap, extendedData *[]byte, structuredData *[]byte) uint32 {
|
||||||
|
offset := uint32(len(*extendedData))
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindStringLiteral:
|
||||||
|
recordExtendedData_StringLiteral(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindNumericLiteral:
|
||||||
|
recordExtendedData_NumericLiteral(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindBigIntLiteral:
|
||||||
|
recordExtendedData_BigIntLiteral(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindRegularExpressionLiteral:
|
||||||
|
recordExtendedData_RegularExpressionLiteral(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindNoSubstitutionTemplateLiteral:
|
||||||
|
recordExtendedData_NoSubstitutionTemplateLiteral(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindTemplateHead:
|
||||||
|
recordExtendedData_TemplateHead(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindTemplateMiddle:
|
||||||
|
recordExtendedData_TemplateMiddle(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindTemplateTail:
|
||||||
|
recordExtendedData_TemplateTail(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
case ast.KindSourceFile:
|
||||||
|
recordExtendedData_SourceFile(node, strs, positionMap, extendedData, structuredData)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown extended data node kind %v", node.Kind))
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
}
|
||||||
161
tools/tsgo/internal/api/encoder/encoder_test.go
Normal file
161
tools/tsgo/internal/api/encoder/encoder_test.go
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
package encoder_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/api/encoder"
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/parser"
|
||||||
|
"github.com/microsoft/typescript-go/internal/repo"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/baseline"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEncodeSourceFile(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/test.ts",
|
||||||
|
Path: "/test.ts",
|
||||||
|
}, "import { bar } from \"bar\";\nexport function foo<T, U>(a: string, b: string): any {}\nfoo();", core.ScriptKindTS)
|
||||||
|
t.Run("baseline", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sourceFile)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
str := formatEncodedSourceFile(buf)
|
||||||
|
baseline.Run(t, "encodeSourceFile.txt", str, baseline.Options{
|
||||||
|
Subfolder: "api",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeSourceFileWithUnicodeEscapes(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/test.ts",
|
||||||
|
Path: "/test.ts",
|
||||||
|
}, `let a = "😃"; let b = "\ud83d\ude03"; let c = "\udc00\ud83d\ude03"; let d = "\ud83d\ud83d\ude03"`, core.ScriptKindTS)
|
||||||
|
t.Run("baseline", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
buf, _, err := encoder.EncodeSourceFile(sourceFile)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
str := formatEncodedSourceFile(buf)
|
||||||
|
baseline.Run(t, "encodeSourceFileWithUnicodeEscapes.txt", str, baseline.Options{
|
||||||
|
Subfolder: "api",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildNodeIndexTableMatchesEncode(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/test.ts",
|
||||||
|
Path: "/test.ts",
|
||||||
|
}, "import { bar } from \"bar\";\nexport function foo<T, U>(a: string, b: string): any {}\nfoo();", core.ScriptKindTS)
|
||||||
|
|
||||||
|
_, encodeTable, err := encoder.EncodeSourceFile(sourceFile)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
buildTable := encoder.BuildNodeIndexTable(sourceFile)
|
||||||
|
|
||||||
|
// Both tables should produce identical Nodes slices
|
||||||
|
assert.Equal(t, len(buildTable.Nodes), len(encodeTable.Nodes), "Nodes slice length mismatch")
|
||||||
|
|
||||||
|
// Every index should map to the same node
|
||||||
|
for i := range encodeTable.Nodes {
|
||||||
|
assert.Equal(t, buildTable.Nodes[i], encodeTable.Nodes[i], "node mismatch at index %d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIndex on both tables should agree for every non-nil node
|
||||||
|
for i, node := range encodeTable.Nodes {
|
||||||
|
if node == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
encIdx := encodeTable.GetIndex(node)
|
||||||
|
buildIdx := buildTable.GetIndex(node)
|
||||||
|
assert.Equal(t, encIdx, uint32(i), "encodeTable.GetIndex mismatch at index %d, node kind=%s", i, node.Kind.String())
|
||||||
|
assert.Equal(t, buildIdx, encIdx, "buildTable.GetIndex mismatch for node kind=%s", node.Kind.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeSourceFile(b *testing.B) {
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(b)
|
||||||
|
filePath := filepath.Join(repo.TypeScriptSubmodulePath(), "src/compiler/checker.ts")
|
||||||
|
fileContent, err := os.ReadFile(filePath)
|
||||||
|
assert.NilError(b, err)
|
||||||
|
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/checker.ts",
|
||||||
|
Path: "/checker.ts",
|
||||||
|
}, string(fileContent), core.ScriptKindTS)
|
||||||
|
|
||||||
|
for b.Loop() {
|
||||||
|
_, _, err := encoder.EncodeSourceFile(sourceFile)
|
||||||
|
assert.NilError(b, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBuildNodeIndexTable(b *testing.B) {
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(b)
|
||||||
|
filePath := filepath.Join(repo.TypeScriptSubmodulePath(), "src/compiler/checker.ts")
|
||||||
|
fileContent, err := os.ReadFile(filePath)
|
||||||
|
assert.NilError(b, err)
|
||||||
|
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/checker.ts",
|
||||||
|
Path: "/checker.ts",
|
||||||
|
}, string(fileContent), core.ScriptKindTS)
|
||||||
|
|
||||||
|
for b.Loop() {
|
||||||
|
encoder.BuildNodeIndexTable(sourceFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readUint32(buf []byte, offset int) uint32 {
|
||||||
|
return binary.LittleEndian.Uint32(buf[offset : offset+4])
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatEncodedSourceFile(encoded []byte) string {
|
||||||
|
var result strings.Builder
|
||||||
|
var getIndent func(parentIndex uint32) string
|
||||||
|
offsetNodes := readUint32(encoded, encoder.HeaderOffsetNodes)
|
||||||
|
offsetStringOffsets := readUint32(encoded, encoder.HeaderOffsetStringOffsets)
|
||||||
|
offsetStrings := readUint32(encoded, encoder.HeaderOffsetStringData)
|
||||||
|
getIndent = func(parentIndex uint32) string {
|
||||||
|
if parentIndex == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return " " + getIndent(readUint32(encoded, int(offsetNodes)+int(parentIndex)*encoder.NodeSize+encoder.NodeOffsetParent))
|
||||||
|
}
|
||||||
|
j := 1
|
||||||
|
for i := int(offsetNodes) + encoder.NodeSize; i < len(encoded); i += encoder.NodeSize {
|
||||||
|
kind := readUint32(encoded, i+encoder.NodeOffsetKind)
|
||||||
|
pos := readUint32(encoded, i+encoder.NodeOffsetPos)
|
||||||
|
end := readUint32(encoded, i+encoder.NodeOffsetEnd)
|
||||||
|
parentIndex := readUint32(encoded, i+encoder.NodeOffsetParent)
|
||||||
|
result.WriteString(getIndent(parentIndex))
|
||||||
|
if kind == encoder.SyntaxKindNodeList {
|
||||||
|
result.WriteString("NodeList")
|
||||||
|
} else {
|
||||||
|
result.WriteString(ast.Kind(kind).String())
|
||||||
|
}
|
||||||
|
data := readUint32(encoded, i+encoder.NodeOffsetData)
|
||||||
|
dataType := data & encoder.NodeDataTypeMask
|
||||||
|
if ast.Kind(kind) == ast.KindIdentifier || (dataType == encoder.NodeDataTypeString) {
|
||||||
|
stringIndex := data & encoder.NodeDataStringIndexMask
|
||||||
|
strStart := readUint32(encoded, int(offsetStringOffsets+stringIndex*4))
|
||||||
|
strEnd := readUint32(encoded, int(offsetStringOffsets+stringIndex*4)+4)
|
||||||
|
str := string(encoded[offsetStrings+strStart : offsetStrings+strEnd])
|
||||||
|
result.WriteString(fmt.Sprintf(" \"%s\"", str))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&result, " [%d, %d), i=%d, next=%d", pos, end, j, encoded[i+encoder.NodeOffsetNext])
|
||||||
|
result.WriteString("\n")
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
68
tools/tsgo/internal/api/encoder/stringtable.go
Normal file
68
tools/tsgo/internal/api/encoder/stringtable.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stringTable struct {
|
||||||
|
fileText string
|
||||||
|
otherStrings *strings.Builder
|
||||||
|
// offsets are pos/end pairs
|
||||||
|
offsets []uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStringTable(fileText string, stringCount int) *stringTable {
|
||||||
|
builder := &strings.Builder{}
|
||||||
|
return &stringTable{
|
||||||
|
fileText: fileText,
|
||||||
|
otherStrings: builder,
|
||||||
|
offsets: make([]uint32, 0, stringCount*2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stringTable) add(text string, kind ast.Kind, pos int, end int) uint32 {
|
||||||
|
index := uint32(len(t.offsets))
|
||||||
|
if kind == ast.KindSourceFile {
|
||||||
|
t.offsets = append(t.offsets, uint32(pos), uint32(end))
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
length := len(text)
|
||||||
|
if end-pos > 0 && end <= len(t.fileText) {
|
||||||
|
// pos includes leading trivia, but we can usually infer the actual start of the
|
||||||
|
// string from the kind and end
|
||||||
|
endOffset := 0
|
||||||
|
if kind == ast.KindStringLiteral || kind == ast.KindTemplateTail || kind == ast.KindNoSubstitutionTemplateLiteral {
|
||||||
|
endOffset = 1
|
||||||
|
}
|
||||||
|
end = end - endOffset
|
||||||
|
start := end - length
|
||||||
|
fileSlice := t.fileText[start:end]
|
||||||
|
if fileSlice == text {
|
||||||
|
t.offsets = append(t.offsets, uint32(start), uint32(end))
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no exact match, so we need to add it to the string table
|
||||||
|
offset := len(t.fileText) + t.otherStrings.Len()
|
||||||
|
t.otherStrings.WriteString(text)
|
||||||
|
t.offsets = append(t.offsets, uint32(offset), uint32(offset+length))
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stringTable) encode() []byte {
|
||||||
|
result := make([]byte, 0, t.encodedLength())
|
||||||
|
result = appendUint32s(result, t.offsets...)
|
||||||
|
result = append(result, t.fileText...)
|
||||||
|
result = append(result, t.otherStrings.String()...)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stringTable) stringLength() int {
|
||||||
|
return len(t.fileText) + t.otherStrings.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stringTable) encodedLength() int {
|
||||||
|
return len(t.offsets)*4 + len(t.fileText) + t.otherStrings.Len()
|
||||||
|
}
|
||||||
14
tools/tsgo/internal/api/encoder/testmain_test.go
Normal file
14
tools/tsgo/internal/api/encoder/testmain_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package encoder_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/baseline"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
core.ApplyDebugStackLimit()
|
||||||
|
defer baseline.Track()()
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
1225
tools/tsgo/internal/api/proto.go
Normal file
1225
tools/tsgo/internal/api/proto.go
Normal file
File diff suppressed because it is too large
Load Diff
83
tools/tsgo/internal/api/proto_test.go
Normal file
83
tools/tsgo/internal/api/proto_test.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package api_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/api"
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/diagnostics"
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
"github.com/microsoft/typescript-go/internal/parser"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDocumentIdentifierUnmarshalJSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
fileName string
|
||||||
|
uri string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "plain string",
|
||||||
|
input: `"foo.ts"`,
|
||||||
|
fileName: "foo.ts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uri object",
|
||||||
|
input: `{"uri":"file:///foo.ts"}`,
|
||||||
|
uri: "file:///foo.ts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uri object with unknown fields",
|
||||||
|
input: `{"uri":"file:///foo.ts","extra":true}`,
|
||||||
|
uri: "file:///foo.ts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty object",
|
||||||
|
input: `{}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid type",
|
||||||
|
input: `42`,
|
||||||
|
err: "expected string or object, got number",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
var d api.DocumentIdentifier
|
||||||
|
err := json.Unmarshal([]byte(tt.input), &d)
|
||||||
|
if tt.err != "" {
|
||||||
|
assert.ErrorContains(t, err, tt.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, d.FileName, tt.fileName)
|
||||||
|
assert.Equal(t, string(d.URI), tt.uri)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDiagnosticResponseUsesUTF16Offsets(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
text := "const 💩 = 1;"
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{FileName: "/unicode.ts"}, text, core.ScriptKindTS)
|
||||||
|
pos := strings.Index(text, "=")
|
||||||
|
assert.Assert(t, pos > 0)
|
||||||
|
end := pos + len("=")
|
||||||
|
|
||||||
|
diag := ast.NewDiagnostic(file, core.NewTextRange(pos, end), diagnostics.Expression_expected)
|
||||||
|
resp := api.NewDiagnosticResponse(diag)
|
||||||
|
|
||||||
|
assert.Equal(t, resp.Pos, 9)
|
||||||
|
assert.Equal(t, resp.End, 10)
|
||||||
|
assert.Equal(t, resp.Pos, file.GetPositionMap().UTF8ToUTF16(pos))
|
||||||
|
assert.Equal(t, resp.End, file.GetPositionMap().UTF8ToUTF16(end))
|
||||||
|
}
|
||||||
22
tools/tsgo/internal/api/protocol.go
Normal file
22
tools/tsgo/internal/api/protocol.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoft/typescript-go/internal/jsonrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message is an alias for jsonrpc.Message for convenience.
|
||||||
|
type Message = jsonrpc.Message
|
||||||
|
|
||||||
|
// Protocol defines the interface for reading and writing API messages.
|
||||||
|
type Protocol interface {
|
||||||
|
// ReadMessage reads the next message from the connection.
|
||||||
|
ReadMessage() (*Message, error)
|
||||||
|
// WriteRequest writes a request message.
|
||||||
|
WriteRequest(id *jsonrpc.ID, method string, params any) error
|
||||||
|
// WriteNotification writes a notification message (no ID).
|
||||||
|
WriteNotification(method string, params any) error
|
||||||
|
// WriteResponse writes a successful response.
|
||||||
|
WriteResponse(id *jsonrpc.ID, result any) error
|
||||||
|
// WriteError writes an error response.
|
||||||
|
WriteError(id *jsonrpc.ID, err *jsonrpc.ResponseError) error
|
||||||
|
}
|
||||||
96
tools/tsgo/internal/api/protocol_jsonrpc.go
Normal file
96
tools/tsgo/internal/api/protocol_jsonrpc.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
"github.com/microsoft/typescript-go/internal/jsonrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JSONRPCProtocol implements the Protocol interface using JSON-RPC 2.0
|
||||||
|
// with the LSP base protocol framing (Content-Length headers).
|
||||||
|
type JSONRPCProtocol struct {
|
||||||
|
reader *jsonrpc.Reader
|
||||||
|
writer *jsonrpc.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Protocol = (*JSONRPCProtocol)(nil)
|
||||||
|
|
||||||
|
// NewJSONRPCProtocol creates a new JSON-RPC protocol handler.
|
||||||
|
func NewJSONRPCProtocol(rw io.ReadWriter) *JSONRPCProtocol {
|
||||||
|
return &JSONRPCProtocol{
|
||||||
|
reader: jsonrpc.NewReader(rw),
|
||||||
|
writer: jsonrpc.NewWriter(rw),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadMessage implements Protocol.
|
||||||
|
func (p *JSONRPCProtocol) ReadMessage() (*Message, error) {
|
||||||
|
data, err := p.reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg Message
|
||||||
|
if err := json.Unmarshal(data, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRequest implements Protocol.
|
||||||
|
func (p *JSONRPCProtocol) WriteRequest(id *jsonrpc.ID, method string, params any) error {
|
||||||
|
msg := jsonrpc.RequestMessage{
|
||||||
|
ID: id,
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.writer.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteNotification implements Protocol.
|
||||||
|
func (p *JSONRPCProtocol) WriteNotification(method string, params any) error {
|
||||||
|
msg := jsonrpc.RequestMessage{
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.writer.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse implements Protocol.
|
||||||
|
func (p *JSONRPCProtocol) WriteResponse(id *jsonrpc.ID, result any) error {
|
||||||
|
if result == nil {
|
||||||
|
result = json.Value("null")
|
||||||
|
}
|
||||||
|
msg := jsonrpc.ResponseMessage{
|
||||||
|
ID: id,
|
||||||
|
Result: result,
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.writer.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteError implements Protocol.
|
||||||
|
func (p *JSONRPCProtocol) WriteError(id *jsonrpc.ID, respErr *jsonrpc.ResponseError) error {
|
||||||
|
msg := jsonrpc.ResponseMessage{
|
||||||
|
ID: id,
|
||||||
|
Error: respErr,
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.writer.Write(data)
|
||||||
|
}
|
||||||
280
tools/tsgo/internal/api/protocol_msgpack.go
Normal file
280
tools/tsgo/internal/api/protocol_msgpack.go
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/json"
|
||||||
|
"github.com/microsoft/typescript-go/internal/jsonrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MessageType represents the type of message in the msgpack protocol.
|
||||||
|
type MessageType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
MessageTypeUnknown MessageType = iota
|
||||||
|
MessageTypeRequest
|
||||||
|
MessageTypeCallResponse
|
||||||
|
MessageTypeCallError
|
||||||
|
MessageTypeResponse
|
||||||
|
MessageTypeError
|
||||||
|
MessageTypeCall
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m MessageType) IsValid() bool {
|
||||||
|
return m >= MessageTypeRequest && m <= MessageTypeCall
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessagePack format constants
|
||||||
|
const (
|
||||||
|
msgpackFixedArray3 byte = 0x93
|
||||||
|
msgpackBin8 byte = 0xC4
|
||||||
|
msgpackBin16 byte = 0xC5
|
||||||
|
msgpackBin32 byte = 0xC6
|
||||||
|
msgpackU8 byte = 0xCC
|
||||||
|
)
|
||||||
|
|
||||||
|
// MessagePackProtocol implements the Protocol interface using a custom
|
||||||
|
// msgpack-based tuple format: [MessageType, method, payload].
|
||||||
|
type MessagePackProtocol struct {
|
||||||
|
r *bufio.Reader
|
||||||
|
w *bufio.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Protocol = (*MessagePackProtocol)(nil)
|
||||||
|
|
||||||
|
// NewMessagePackProtocol creates a new msgpack protocol handler.
|
||||||
|
func NewMessagePackProtocol(rw io.ReadWriter) *MessagePackProtocol {
|
||||||
|
return &MessagePackProtocol{
|
||||||
|
r: bufio.NewReader(rw),
|
||||||
|
w: bufio.NewWriter(rw),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadMessage implements Protocol.
|
||||||
|
func (p *MessagePackProtocol) ReadMessage() (*Message, error) {
|
||||||
|
msgType, method, payload, err := p.readTuple()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert msgpack message type to JSON-RPC message
|
||||||
|
msg := &Message{}
|
||||||
|
|
||||||
|
switch msgType {
|
||||||
|
case MessageTypeRequest:
|
||||||
|
// Client request - needs an ID for response
|
||||||
|
// We use the method as a pseudo-ID since this protocol doesn't have explicit IDs
|
||||||
|
id := jsonrpc.NewIDString(method)
|
||||||
|
msg.ID = id
|
||||||
|
msg.Method = method
|
||||||
|
msg.Params = payload
|
||||||
|
case MessageTypeCallResponse:
|
||||||
|
// Response to our Call - use method as ID
|
||||||
|
// Note: Method must be empty for IsResponse() to return true
|
||||||
|
id := jsonrpc.NewIDString(method)
|
||||||
|
msg.ID = id
|
||||||
|
msg.Result = payload
|
||||||
|
case MessageTypeCallError:
|
||||||
|
// Error response to our Call
|
||||||
|
// Note: Method must be empty for IsResponse() to return true
|
||||||
|
id := jsonrpc.NewIDString(method)
|
||||||
|
msg.ID = id
|
||||||
|
msg.Error = &jsonrpc.ResponseError{
|
||||||
|
Code: jsonrpc.CodeInternalError,
|
||||||
|
Message: string(payload),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected message type: %d", msgType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePackProtocol) readTuple() (MessageType, string, []byte, error) {
|
||||||
|
// Read fixed array marker (0x93 = 3-element array)
|
||||||
|
t, err := p.r.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", nil, err
|
||||||
|
}
|
||||||
|
if t != msgpackFixedArray3 {
|
||||||
|
return 0, "", nil, fmt.Errorf("%w: expected fixed 3-element array (0x93), received: 0x%02x", ErrInvalidRequest, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read message type - can be positive fixint (0x00-0x7F) or uint8 (0xCC + value)
|
||||||
|
t, err = p.r.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", nil, err
|
||||||
|
}
|
||||||
|
var rawType byte
|
||||||
|
if t <= 0x7F {
|
||||||
|
// Positive fixint - the byte IS the value
|
||||||
|
rawType = t
|
||||||
|
} else if t == msgpackU8 {
|
||||||
|
// uint8 marker - next byte is the value
|
||||||
|
rawType, err = p.r.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0, "", nil, fmt.Errorf("%w: expected positive fixint or uint8 marker, received: 0x%02x", ErrInvalidRequest, t)
|
||||||
|
}
|
||||||
|
msgType := MessageType(rawType)
|
||||||
|
if !msgType.IsValid() {
|
||||||
|
return 0, "", nil, fmt.Errorf("%w: unknown message type: %d", ErrInvalidRequest, msgType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read method (binary)
|
||||||
|
methodBytes, err := p.readBin()
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", nil, err
|
||||||
|
}
|
||||||
|
method := string(methodBytes)
|
||||||
|
|
||||||
|
// Read payload (binary)
|
||||||
|
payload, err := p.readBin()
|
||||||
|
if err != nil {
|
||||||
|
return 0, "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgType, method, payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePackProtocol) readBin() ([]byte, error) {
|
||||||
|
t, err := p.r.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var size uint
|
||||||
|
switch t {
|
||||||
|
case msgpackBin8:
|
||||||
|
var size8 uint8
|
||||||
|
if err = binary.Read(p.r, binary.BigEndian, &size8); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
size = uint(size8)
|
||||||
|
case msgpackBin16:
|
||||||
|
var size16 uint16
|
||||||
|
if err = binary.Read(p.r, binary.BigEndian, &size16); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
size = uint(size16)
|
||||||
|
case msgpackBin32:
|
||||||
|
var size32 uint32
|
||||||
|
if err = binary.Read(p.r, binary.BigEndian, &size32); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
size = uint(size32)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("%w: expected binary data (0xc4-0xc6), received: 0x%02x", ErrInvalidRequest, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := make([]byte, size)
|
||||||
|
if _, err := io.ReadFull(p.r, payload); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRequest implements Protocol.
|
||||||
|
func (p *MessagePackProtocol) WriteRequest(id *jsonrpc.ID, method string, params any) error {
|
||||||
|
// For msgpack protocol, requests from server are "Call" type
|
||||||
|
payload, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.writeTuple(MessageTypeCall, method, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteNotification implements Protocol.
|
||||||
|
func (p *MessagePackProtocol) WriteNotification(method string, params any) error {
|
||||||
|
// Msgpack protocol doesn't distinguish notifications from calls
|
||||||
|
return p.WriteRequest(nil, method, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse implements Protocol.
|
||||||
|
func (p *MessagePackProtocol) WriteResponse(id *jsonrpc.ID, result any) error {
|
||||||
|
method := ""
|
||||||
|
if id != nil {
|
||||||
|
method = id.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Check if result is raw binary (for efficient binary transport)
|
||||||
|
if raw, ok := result.(RawBinary); ok {
|
||||||
|
payload = []byte(raw)
|
||||||
|
} else {
|
||||||
|
payload, err = json.Marshal(result)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.writeTuple(MessageTypeResponse, method, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteError implements Protocol.
|
||||||
|
func (p *MessagePackProtocol) WriteError(id *jsonrpc.ID, respErr *jsonrpc.ResponseError) error {
|
||||||
|
method := ""
|
||||||
|
if id != nil {
|
||||||
|
method = id.String()
|
||||||
|
}
|
||||||
|
return p.writeTuple(MessageTypeError, method, []byte(respErr.Message))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePackProtocol) writeTuple(msgType MessageType, method string, payload []byte) error {
|
||||||
|
// Write fixed array marker
|
||||||
|
if err := p.w.WriteByte(msgpackFixedArray3); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Write message type as positive fixint (values 0-127 are written directly)
|
||||||
|
if err := p.w.WriteByte(byte(msgType)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Write method
|
||||||
|
if err := p.writeBin([]byte(method)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Write payload
|
||||||
|
if err := p.writeBin(payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *MessagePackProtocol) writeBin(data []byte) error {
|
||||||
|
length := len(data)
|
||||||
|
if length < 256 {
|
||||||
|
if err := p.w.WriteByte(msgpackBin8); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.w.WriteByte(byte(length)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if length < 1<<16 {
|
||||||
|
if err := p.w.WriteByte(msgpackBin16); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(p.w, binary.BigEndian, uint16(length)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := p.w.WriteByte(msgpackBin32); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Write(p.w, binary.BigEndian, uint32(length)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := p.w.Write(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawBinary is a marker type for binary data that should be written
|
||||||
|
// directly by MessagePackProtocol instead of being JSON-encoded.
|
||||||
|
type RawBinary []byte
|
||||||
124
tools/tsgo/internal/api/server.go
Normal file
124
tools/tsgo/internal/api/server.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
||||||
|
"github.com/microsoft/typescript-go/internal/project"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StdioServerOptions configures the STDIO-based API server.
|
||||||
|
type StdioServerOptions struct {
|
||||||
|
In io.ReadCloser
|
||||||
|
Out io.WriteCloser
|
||||||
|
Err io.Writer
|
||||||
|
Cwd string
|
||||||
|
DefaultLibraryPath string
|
||||||
|
// PipePath, if set, listens on a named pipe (Windows) or Unix domain
|
||||||
|
// socket instead of using In/Out for communication.
|
||||||
|
PipePath string
|
||||||
|
// Callbacks specifies which filesystem operations should be delegated
|
||||||
|
// to the client (e.g., "readFile", "fileExists"). Empty means no callbacks.
|
||||||
|
Callbacks []string
|
||||||
|
// Async enables JSON-RPC protocol with async connection handling.
|
||||||
|
// When false (default), uses MessagePack protocol with sync connection.
|
||||||
|
Async bool
|
||||||
|
// CollectTiming enables per-request server processing-time measurement.
|
||||||
|
// When enabled, the server accumulates each request's processing time into
|
||||||
|
// running totals and a recent-request ring buffer. Response messages are
|
||||||
|
// left unchanged; the client folds this data into its own timing snapshot
|
||||||
|
// on demand via getServerTiming / resetServerTiming requests.
|
||||||
|
CollectTiming bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdioServer runs an API session over STDIO using MessagePack protocol.
|
||||||
|
// This is the entry point for the synchronous STDIO-based API used by
|
||||||
|
// native TypeScript tooling integration.
|
||||||
|
type StdioServer struct {
|
||||||
|
options *StdioServerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStdioServer creates a new STDIO-based API server.
|
||||||
|
func NewStdioServer(options *StdioServerOptions) *StdioServer {
|
||||||
|
if options.Cwd == "" {
|
||||||
|
panic("StdioServerOptions.Cwd is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StdioServer{
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts the server and blocks until the connection closes.
|
||||||
|
func (s *StdioServer) Run(ctx context.Context) error {
|
||||||
|
var transport Transport
|
||||||
|
if s.options.PipePath != "" {
|
||||||
|
t, err := NewPipeTransport(s.options.PipePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create pipe transport: %w", err)
|
||||||
|
}
|
||||||
|
defer t.Close()
|
||||||
|
transport = t
|
||||||
|
} else {
|
||||||
|
t := NewStdioTransport(s.options.In, s.options.Out)
|
||||||
|
defer t.Close()
|
||||||
|
transport = t
|
||||||
|
}
|
||||||
|
|
||||||
|
fs := bundled.WrapFS(osvfs.FS())
|
||||||
|
|
||||||
|
// Wrap the base FS with callbackFS if callbacks are requested
|
||||||
|
var callbackFS *callbackFS
|
||||||
|
if len(s.options.Callbacks) > 0 {
|
||||||
|
callbackFS = newCallbackFS(fs, s.options.Callbacks)
|
||||||
|
fs = callbackFS
|
||||||
|
}
|
||||||
|
|
||||||
|
projectSession := project.NewSession(&project.SessionInit{
|
||||||
|
BackgroundCtx: ctx,
|
||||||
|
Logger: nil, // TODO: Add logging support
|
||||||
|
FS: fs,
|
||||||
|
Options: &project.SessionOptions{
|
||||||
|
CurrentDirectory: s.options.Cwd,
|
||||||
|
DefaultLibraryPath: s.options.DefaultLibraryPath,
|
||||||
|
PositionEncoding: lsproto.PositionEncodingKindUTF8,
|
||||||
|
LoggingEnabled: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
session := NewSession(projectSession, &SessionOptions{
|
||||||
|
UseBinaryResponses: !s.options.Async, // Only msgpack uses binary responses
|
||||||
|
})
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
// Accept connection from transport
|
||||||
|
rwc, err := transport.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to accept connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create protocol and connection based on async mode
|
||||||
|
var conn Conn
|
||||||
|
if s.options.Async {
|
||||||
|
protocol := NewJSONRPCProtocol(rwc)
|
||||||
|
asyncConn := NewAsyncConnWithProtocol(rwc, protocol, session)
|
||||||
|
asyncConn.SetCollectTiming(s.options.CollectTiming)
|
||||||
|
conn = asyncConn
|
||||||
|
} else {
|
||||||
|
protocol := NewMessagePackProtocol(rwc)
|
||||||
|
syncConn := NewSyncConn(rwc, protocol, session)
|
||||||
|
syncConn.SetCollectTiming(s.options.CollectTiming)
|
||||||
|
conn = syncConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// If callbacks are enabled, set the connection on the FS
|
||||||
|
if callbackFS != nil {
|
||||||
|
callbackFS.SetConnection(ctx, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn.Run(ctx)
|
||||||
|
}
|
||||||
3210
tools/tsgo/internal/api/session.go
Normal file
3210
tools/tsgo/internal/api/session.go
Normal file
File diff suppressed because it is too large
Load Diff
255
tools/tsgo/internal/api/session_apistate_test.go
Normal file
255
tools/tsgo/internal/api/session_apistate_test.go
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/projecttestutil"
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestSessionTracksAndReleasesAPIRefs verifies that an API session holds at most
|
||||||
|
// one ref per opened project/file (opens are idempotent) and releases exactly
|
||||||
|
// those refs when the session is closed, so it never leaks or over-releases refs
|
||||||
|
// in the underlying (potentially shared) project session.
|
||||||
|
func TestSessionTracksAndReleasesAPIRefs(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if !bundled.Embedded {
|
||||||
|
t.Skip("bundled files are not embedded")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("project opens are idempotent and released on close", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
const configFileName = "/home/projects/p/tsconfig.json"
|
||||||
|
files := map[string]any{
|
||||||
|
configFileName: `{ "compilerOptions": { "strict": true } }`,
|
||||||
|
"/home/projects/p/src/index.ts": `export const x = 1;`,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
|
||||||
|
_, err := session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenProjects: []DocumentIdentifier{{FileName: configFileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openProjects.Len(), 1)
|
||||||
|
|
||||||
|
// Opening the same project again must not take an additional ref.
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenProjects: []DocumentIdentifier{{FileName: configFileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openProjects.Len(), 1)
|
||||||
|
|
||||||
|
assert.Assert(t, projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path(configFileName)) != nil)
|
||||||
|
|
||||||
|
// Closing the session releases the single API ref, so the project is no
|
||||||
|
// longer kept loaded.
|
||||||
|
session.Close()
|
||||||
|
assert.Equal(t, session.openProjects.Len(), 0)
|
||||||
|
assert.Assert(t, projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path(configFileName)) == nil)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("explicit close releases the project ref", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
const configFileName = "/home/projects/p/tsconfig.json"
|
||||||
|
files := map[string]any{
|
||||||
|
configFileName: `{ "compilerOptions": { "strict": true } }`,
|
||||||
|
"/home/projects/p/src/index.ts": `export const x = 1;`,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
_, err := session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenProjects: []DocumentIdentifier{{FileName: configFileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openProjects.Len(), 1)
|
||||||
|
assert.Assert(t, projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path(configFileName)) != nil)
|
||||||
|
|
||||||
|
// Closing a project we hold releases the ref and unloads the project.
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
CloseProjects: []DocumentIdentifier{{FileName: configFileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openProjects.Len(), 0)
|
||||||
|
assert.Assert(t, projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path(configFileName)) == nil)
|
||||||
|
|
||||||
|
// Closing a project we don't hold is a no-op (never over-releases).
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
CloseProjects: []DocumentIdentifier{{FileName: configFileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openProjects.Len(), 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("file opens are idempotent and released on close", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
const fileName = "/home/projects/p/src/index.ts"
|
||||||
|
files := map[string]any{
|
||||||
|
"/home/projects/p/tsconfig.json": `{ "compilerOptions": { "strict": true } }`,
|
||||||
|
fileName: `export const x = 1;`,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
|
||||||
|
_, err := session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenFiles: []DocumentIdentifier{{FileName: fileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 1)
|
||||||
|
|
||||||
|
// Re-opening the same file must not take an additional ref.
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenFiles: []DocumentIdentifier{{FileName: fileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 1)
|
||||||
|
|
||||||
|
// The file should resolve to the configured project via ancestor search.
|
||||||
|
assert.Assert(t, projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/p/tsconfig.json")) != nil)
|
||||||
|
|
||||||
|
// Closing a file we don't hold is a no-op (never over-releases).
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
CloseFiles: []DocumentIdentifier{{FileName: "/home/projects/p/other.ts"}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 1)
|
||||||
|
|
||||||
|
// Explicitly closing the held file releases the ref.
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
CloseFiles: []DocumentIdentifier{{FileName: fileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 0)
|
||||||
|
|
||||||
|
// Closing the file also tears down the configured project that was
|
||||||
|
// auto-loaded to serve it, instead of leaking it.
|
||||||
|
assert.Assert(t,
|
||||||
|
projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/p/tsconfig.json")) == nil,
|
||||||
|
"configured project auto-loaded for the API-opened file should be unloaded after close",
|
||||||
|
)
|
||||||
|
|
||||||
|
session.Close()
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("relative file paths normalize consistently for open and close", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// The project session's current directory is "/", so a relative path
|
||||||
|
// resolves to the corresponding absolute path.
|
||||||
|
files := map[string]any{
|
||||||
|
"/src/tsconfig.json": `{ "compilerOptions": { "strict": true } }`,
|
||||||
|
"/src/index.ts": `export const x = 1;`,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
// Open via a relative path; it should be tracked under the absolute path
|
||||||
|
// and resolve to the containing configured project.
|
||||||
|
openResp, err := session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenFiles: []DocumentIdentifier{{FileName: "src/index.ts"}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 1)
|
||||||
|
assert.Assert(t, session.openFiles.Has(tspath.Path("/src/index.ts")))
|
||||||
|
assert.Assert(t, projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path("/src/tsconfig.json")) != nil)
|
||||||
|
|
||||||
|
// getDefaultProjectForFile must also resolve a relative path to the same
|
||||||
|
// configured project (it builds a URI from the identifier internally).
|
||||||
|
proj, err := session.handleGetDefaultProjectForFile(context.Background(), &GetDefaultProjectForFileParams{
|
||||||
|
Snapshot: openResp.Snapshot,
|
||||||
|
File: DocumentIdentifier{FileName: "src/index.ts"},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, proj != nil, "relative path should resolve to a default project")
|
||||||
|
assert.Equal(t, proj.ConfigFileName, "/src/tsconfig.json")
|
||||||
|
|
||||||
|
// Re-opening via the absolute path must match the relative open (no new ref).
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenFiles: []DocumentIdentifier{{FileName: "/src/index.ts"}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 1)
|
||||||
|
|
||||||
|
// Closing via a relative path must match the path stored when opening.
|
||||||
|
_, err = session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
CloseFiles: []DocumentIdentifier{{FileName: "src/index.ts"}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, session.openFiles.Len(), 0)
|
||||||
|
assert.Assert(t,
|
||||||
|
projectSession.Snapshot().ProjectCollection.ConfiguredProject(tspath.Path("/src/tsconfig.json")) == nil,
|
||||||
|
"configured project should be unloaded after closing the relatively-pathed file",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUpdateSnapshotResponseSkipsUnloadedAncestorProject verifies that API
|
||||||
|
// updateSnapshot does not report unloaded ancestor project placeholders. This
|
||||||
|
// covers the case where opening a file loads its nearest configured project
|
||||||
|
// while solution search discovers an ancestor tsconfig placeholder whose command
|
||||||
|
// line is still nil.
|
||||||
|
func TestUpdateSnapshotResponseSkipsUnloadedAncestorProject(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if !bundled.Embedded {
|
||||||
|
t.Skip("bundled files are not embedded")
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
nestedConfigFileName = "/repo/packages/app/tsconfig.json"
|
||||||
|
ancestorConfigFileName = "/repo/packages/tsconfig.json"
|
||||||
|
fileName = "/repo/packages/app/src/index.ts"
|
||||||
|
)
|
||||||
|
files := map[string]any{
|
||||||
|
ancestorConfigFileName: `{ "files": [] }`,
|
||||||
|
nestedConfigFileName: `{
|
||||||
|
"compilerOptions": { "composite": true },
|
||||||
|
"include": ["**/*"]
|
||||||
|
}`,
|
||||||
|
fileName: `let s: string = 1234;`,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
|
||||||
|
projectSession.DidOpenFile(context.Background(), lsproto.DocumentUri("file://"+fileName), 1, files[fileName].(string), lsproto.LanguageKindTypeScript)
|
||||||
|
snapshot := projectSession.Snapshot()
|
||||||
|
nestedProject := snapshot.ProjectCollection.ConfiguredProject(tspath.Path(nestedConfigFileName))
|
||||||
|
assert.Assert(t, nestedProject != nil)
|
||||||
|
assert.Assert(t, nestedProject.CommandLine != nil)
|
||||||
|
ancestorProject := snapshot.ProjectCollection.ConfiguredProject(tspath.Path(ancestorConfigFileName))
|
||||||
|
assert.Assert(t, ancestorProject != nil)
|
||||||
|
assert.Assert(t, ancestorProject.CommandLine == nil)
|
||||||
|
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
response, err := session.handleUpdateSnapshot(context.Background(), &UpdateSnapshotParams{
|
||||||
|
OpenProjects: []DocumentIdentifier{{FileName: nestedConfigFileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
var foundNestedProject bool
|
||||||
|
var foundAncestorProject bool
|
||||||
|
for _, project := range response.Projects {
|
||||||
|
switch project.ConfigFileName {
|
||||||
|
case nestedConfigFileName:
|
||||||
|
foundNestedProject = true
|
||||||
|
assert.Assert(t, project.RootFiles != nil)
|
||||||
|
assert.Assert(t, project.CompilerOptions != nil)
|
||||||
|
case ancestorConfigFileName:
|
||||||
|
foundAncestorProject = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Assert(t, foundNestedProject)
|
||||||
|
assert.Assert(t, !foundAncestorProject)
|
||||||
|
}
|
||||||
141
tools/tsgo/internal/api/session_completion_test.go
Normal file
141
tools/tsgo/internal/api/session_completion_test.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/projecttestutil"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestCompletionSymbolTypeIsResolvable reproduces a crash where requesting the
|
||||||
|
// type of a completion-provided symbol panicked with a nil pointer dereference.
|
||||||
|
//
|
||||||
|
// Completion ran on an ephemeral query checker (default lifetime), so members of
|
||||||
|
// a generic type such as `string[]` (= Array<string>) were returned as
|
||||||
|
// *instantiated* symbols whose per-checker instantiation links live only on that
|
||||||
|
// query checker. GetTypeOfSymbol runs on the persistent API checker — a
|
||||||
|
// different instance — where those links are absent, so getTypeOfInstantiatedSymbol
|
||||||
|
// dereferenced a nil target and brought down the connection.
|
||||||
|
//
|
||||||
|
// The fix pins symbol-producing completion to the API checker, so the returned
|
||||||
|
// handles resolve on the same checker the client re-queries.
|
||||||
|
func TestCompletionSymbolTypeIsResolvable(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if !bundled.Embedded {
|
||||||
|
t.Skip("bundled files are not embedded")
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = "/home/projects/p/src/index.ts"
|
||||||
|
// The caret sits right after `people.`, requesting members of `string[]`.
|
||||||
|
const content = "declare const people: string[];\npeople."
|
||||||
|
|
||||||
|
files := map[string]any{
|
||||||
|
"/home/projects/p/tsconfig.json": `{ "compilerOptions": { "strict": true } }`,
|
||||||
|
fileName: content,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
snapshotResp, err := session.handleUpdateSnapshot(ctx, &UpdateSnapshotParams{
|
||||||
|
OpenFiles: []DocumentIdentifier{{FileName: fileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
proj, err := session.handleGetDefaultProjectForFile(ctx, &GetDefaultProjectForFileParams{
|
||||||
|
Snapshot: snapshotResp.Snapshot,
|
||||||
|
File: DocumentIdentifier{FileName: fileName},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, proj != nil, "file should resolve to a default project")
|
||||||
|
|
||||||
|
// content is pure ASCII, so the UTF-16 caret offset equals the byte length.
|
||||||
|
completions, err := session.handleGetCompletionsAtPosition(ctx, &GetCompletionsAtPositionParams{
|
||||||
|
Snapshot: snapshotResp.Snapshot,
|
||||||
|
Project: proj.Id,
|
||||||
|
File: DocumentIdentifier{FileName: fileName},
|
||||||
|
Position: uint32(len(content)),
|
||||||
|
IncludeSymbol: true,
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, completions != nil, "expected a completion list for array members")
|
||||||
|
|
||||||
|
// Resolving the type of every completion symbol must not panic, and known
|
||||||
|
// members like `push` must produce a concrete type.
|
||||||
|
var sawSymbol, sawPush bool
|
||||||
|
for _, entry := range completions.Entries {
|
||||||
|
if entry.Symbol == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sawSymbol = true
|
||||||
|
typeResp, err := session.handleGetTypeOfSymbol(ctx, &GetTypeOfSymbolParams{
|
||||||
|
Snapshot: snapshotResp.Snapshot,
|
||||||
|
Project: proj.Id,
|
||||||
|
Symbol: entry.Symbol.Id,
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, typeResp != nil, "type of completion symbol %q should resolve", entry.Name)
|
||||||
|
if entry.Name == "push" {
|
||||||
|
sawPush = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Assert(t, sawSymbol, "completion entries should include resolvable symbols")
|
||||||
|
assert.Assert(t, sawPush, "array member completions should include `push`")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCompletionOnInferredProject reproduces a crash where requesting completions
|
||||||
|
// for a loose file — one not part of any tsconfig.json, so it resolves to an
|
||||||
|
// inferred project — panicked with "ConfigFilePath called on non-configured
|
||||||
|
// project".
|
||||||
|
//
|
||||||
|
// setupLanguageService called Project.ConfigFilePath(), which is only valid for
|
||||||
|
// configured projects and panics for inferred ones. The fix uses Project.ID(),
|
||||||
|
// which returns the project's path for both configured and inferred projects without panicking.
|
||||||
|
func TestCompletionOnInferredProject(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if !bundled.Embedded {
|
||||||
|
t.Skip("bundled files are not embedded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// No tsconfig.json anywhere, so this file belongs to an inferred project.
|
||||||
|
const fileName = "/home/projects/p/src/index.ts"
|
||||||
|
const content = "declare const people: string[];\npeople."
|
||||||
|
|
||||||
|
files := map[string]any{
|
||||||
|
fileName: content,
|
||||||
|
}
|
||||||
|
projectSession, _ := projecttestutil.Setup(files)
|
||||||
|
defer projectSession.Close()
|
||||||
|
session := NewSession(projectSession, nil)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
snapshotResp, err := session.handleUpdateSnapshot(ctx, &UpdateSnapshotParams{
|
||||||
|
OpenFiles: []DocumentIdentifier{{FileName: fileName}},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
proj, err := session.handleGetDefaultProjectForFile(ctx, &GetDefaultProjectForFileParams{
|
||||||
|
Snapshot: snapshotResp.Snapshot,
|
||||||
|
File: DocumentIdentifier{FileName: fileName},
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, proj != nil, "file should resolve to an inferred default project")
|
||||||
|
|
||||||
|
// This request previously panicked in setupLanguageService.
|
||||||
|
// content is pure ASCII, so the UTF-16 caret offset equals the byte length.
|
||||||
|
completions, err := session.handleGetCompletionsAtPosition(ctx, &GetCompletionsAtPositionParams{
|
||||||
|
Snapshot: snapshotResp.Snapshot,
|
||||||
|
Project: proj.Id,
|
||||||
|
File: DocumentIdentifier{FileName: fileName},
|
||||||
|
Position: uint32(len(content)),
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, completions != nil, "expected a completion list for array members")
|
||||||
|
}
|
||||||
30
tools/tsgo/internal/api/stringer_generated.go
Normal file
30
tools/tsgo/internal/api/stringer_generated.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Code generated by "stringer -type=MessageType -output=stringer_generated.go"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[MessageTypeUnknown-0]
|
||||||
|
_ = x[MessageTypeRequest-1]
|
||||||
|
_ = x[MessageTypeCallResponse-2]
|
||||||
|
_ = x[MessageTypeCallError-3]
|
||||||
|
_ = x[MessageTypeResponse-4]
|
||||||
|
_ = x[MessageTypeError-5]
|
||||||
|
_ = x[MessageTypeCall-6]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _MessageType_name = "MessageTypeUnknownMessageTypeRequestMessageTypeCallResponseMessageTypeCallErrorMessageTypeResponseMessageTypeErrorMessageTypeCall"
|
||||||
|
|
||||||
|
var _MessageType_index = [...]uint8{0, 18, 36, 59, 79, 98, 114, 129}
|
||||||
|
|
||||||
|
func (i MessageType) String() string {
|
||||||
|
idx := int(i) - 0
|
||||||
|
if i < 0 || idx >= len(_MessageType_index)-1 {
|
||||||
|
return "MessageType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _MessageType_name[_MessageType_index[idx]:_MessageType_index[idx+1]]
|
||||||
|
}
|
||||||
136
tools/tsgo/internal/api/timing.go
Normal file
136
tools/tsgo/internal/api/timing.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// serverRecentRequestCapacity is the number of most-recent requests retained in
|
||||||
|
// the server-side timing ring buffer.
|
||||||
|
const serverRecentRequestCapacity = 5
|
||||||
|
|
||||||
|
// serverRequestTiming is a single server-side request's processing-time sample.
|
||||||
|
type serverRequestTiming struct {
|
||||||
|
// Method is the API method that was handled.
|
||||||
|
Method string `json:"method"`
|
||||||
|
// ProcessingTimeMs is the wall-clock time the server spent handling the
|
||||||
|
// request, in milliseconds.
|
||||||
|
ProcessingTimeMs float64 `json:"processingTimeMs"`
|
||||||
|
// Timestamp is the Unix time in milliseconds when the request completed.
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverTimingTotals holds running totals accumulated across every handled request.
|
||||||
|
type serverTimingTotals struct {
|
||||||
|
// RequestCount is the total number of requests measured.
|
||||||
|
RequestCount uint64 `json:"requestCount"`
|
||||||
|
// TotalProcessingTimeMs is the sum of server processing time, in milliseconds.
|
||||||
|
TotalProcessingTimeMs float64 `json:"totalProcessingTimeMs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverTimingInfo is a point-in-time snapshot of collected server timing,
|
||||||
|
// returned to clients in response to a getServerTiming request.
|
||||||
|
type serverTimingInfo struct {
|
||||||
|
// Enabled reports whether server-side timing collection is active.
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
// Totals are the running totals across every handled request.
|
||||||
|
Totals serverTimingTotals `json:"totals"`
|
||||||
|
// RecentRequests are the most recent requests, oldest to newest, up to
|
||||||
|
// serverRecentRequestCapacity.
|
||||||
|
RecentRequests []serverRequestTiming `json:"recentRequests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// timingCollector accumulates per-request server processing times into running
|
||||||
|
// totals and a fixed-size ring buffer of the most recent requests. It is safe
|
||||||
|
// for concurrent use so the async connection can record from multiple request
|
||||||
|
// goroutines.
|
||||||
|
type timingCollector struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
totals serverTimingTotals
|
||||||
|
// ring holds up to serverRecentRequestCapacity entries; once full, head
|
||||||
|
// marks the oldest entry.
|
||||||
|
ring []serverRequestTiming
|
||||||
|
head int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTimingCollector() *timingCollector {
|
||||||
|
return &timingCollector{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// record adds a single request's processing time to the totals and ring buffer.
|
||||||
|
func (c *timingCollector) record(method string, d time.Duration) {
|
||||||
|
processingMs := durationToMillis(d)
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
c.totals.RequestCount++
|
||||||
|
c.totals.TotalProcessingTimeMs += processingMs
|
||||||
|
|
||||||
|
entry := serverRequestTiming{
|
||||||
|
Method: method,
|
||||||
|
ProcessingTimeMs: processingMs,
|
||||||
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
}
|
||||||
|
if len(c.ring) < serverRecentRequestCapacity {
|
||||||
|
c.ring = append(c.ring, entry)
|
||||||
|
} else {
|
||||||
|
c.ring[c.head] = entry
|
||||||
|
c.head = (c.head + 1) % serverRecentRequestCapacity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// snapshot returns a copy of the currently collected timing information, with
|
||||||
|
// recent requests ordered from oldest to newest.
|
||||||
|
func (c *timingCollector) snapshot() serverTimingInfo {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
recent := make([]serverRequestTiming, 0, len(c.ring))
|
||||||
|
for i := range c.ring {
|
||||||
|
recent = append(recent, c.ring[(c.head+i)%len(c.ring)])
|
||||||
|
}
|
||||||
|
return serverTimingInfo{
|
||||||
|
Enabled: true,
|
||||||
|
Totals: c.totals,
|
||||||
|
RecentRequests: recent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset clears all accumulated totals and recent-request history.
|
||||||
|
func (c *timingCollector) reset() {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
c.totals = serverTimingTotals{}
|
||||||
|
c.ring = nil
|
||||||
|
c.head = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverTimingSnapshot returns the collector's snapshot, or a disabled snapshot
|
||||||
|
// when timing collection is not enabled (collector is nil).
|
||||||
|
func serverTimingSnapshot(c *timingCollector) serverTimingInfo {
|
||||||
|
if c == nil {
|
||||||
|
return disabledServerTimingInfo()
|
||||||
|
}
|
||||||
|
return c.snapshot()
|
||||||
|
}
|
||||||
|
|
||||||
|
// disabledServerTimingInfo is the snapshot returned when timing collection is
|
||||||
|
// not enabled.
|
||||||
|
func disabledServerTimingInfo() serverTimingInfo {
|
||||||
|
return serverTimingInfo{
|
||||||
|
Enabled: false,
|
||||||
|
RecentRequests: []serverRequestTiming{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// durationToMillis converts a duration to fractional milliseconds, clamped to be
|
||||||
|
// non-negative. It preserves sub-microsecond precision by converting from the
|
||||||
|
// full nanosecond duration.
|
||||||
|
func durationToMillis(d time.Duration) float64 {
|
||||||
|
if d < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return float64(d) / float64(time.Millisecond)
|
||||||
|
}
|
||||||
95
tools/tsgo/internal/api/timing_test.go
Normal file
95
tools/tsgo/internal/api/timing_test.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTimingCollector(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("accumulates totals and records recent requests", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c := newTimingCollector()
|
||||||
|
c.record("getSourceFile", 2*time.Millisecond)
|
||||||
|
c.record("getSymbolAtPosition", 500*time.Microsecond)
|
||||||
|
|
||||||
|
snap := c.snapshot()
|
||||||
|
assert.Equal(t, snap.Enabled, true)
|
||||||
|
assert.Equal(t, snap.Totals.RequestCount, uint64(2))
|
||||||
|
assert.Equal(t, snap.Totals.TotalProcessingTimeMs, 2.5)
|
||||||
|
assert.Equal(t, len(snap.RecentRequests), 2)
|
||||||
|
assert.Equal(t, snap.RecentRequests[0].Method, "getSourceFile")
|
||||||
|
assert.Equal(t, snap.RecentRequests[0].ProcessingTimeMs, 2.0)
|
||||||
|
assert.Equal(t, snap.RecentRequests[1].Method, "getSymbolAtPosition")
|
||||||
|
assert.Equal(t, snap.RecentRequests[1].ProcessingTimeMs, 0.5)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ring buffer retains only the most recent requests, oldest to newest", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c := newTimingCollector()
|
||||||
|
methods := []string{"a", "b", "c", "d", "e", "f", "g"}
|
||||||
|
for _, m := range methods {
|
||||||
|
c.record(m, time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
snap := c.snapshot()
|
||||||
|
assert.Equal(t, snap.Totals.RequestCount, uint64(7))
|
||||||
|
assert.Equal(t, len(snap.RecentRequests), serverRecentRequestCapacity)
|
||||||
|
|
||||||
|
// Expect the last 5 methods, oldest to newest.
|
||||||
|
want := methods[len(methods)-serverRecentRequestCapacity:]
|
||||||
|
for i, w := range want {
|
||||||
|
assert.Equal(t, snap.RecentRequests[i].Method, w)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("negative durations clamp to zero", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c := newTimingCollector()
|
||||||
|
c.record("x", -5*time.Second)
|
||||||
|
snap := c.snapshot()
|
||||||
|
assert.Equal(t, snap.Totals.TotalProcessingTimeMs, 0.0)
|
||||||
|
assert.Equal(t, snap.RecentRequests[0].ProcessingTimeMs, 0.0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerTimingSnapshotDisabled(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
snap := serverTimingSnapshot(nil)
|
||||||
|
assert.Equal(t, snap.Enabled, false)
|
||||||
|
assert.Equal(t, snap.Totals.RequestCount, uint64(0))
|
||||||
|
assert.Equal(t, len(snap.RecentRequests), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimingCollectorReset(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c := newTimingCollector()
|
||||||
|
c.record("a", time.Millisecond)
|
||||||
|
c.record("b", time.Millisecond)
|
||||||
|
c.reset()
|
||||||
|
|
||||||
|
snap := c.snapshot()
|
||||||
|
assert.Equal(t, snap.Enabled, true)
|
||||||
|
assert.Equal(t, snap.Totals.RequestCount, uint64(0))
|
||||||
|
assert.Equal(t, snap.Totals.TotalProcessingTimeMs, 0.0)
|
||||||
|
assert.Equal(t, len(snap.RecentRequests), 0)
|
||||||
|
|
||||||
|
// The collector remains usable after a reset.
|
||||||
|
c.record("c", 2*time.Millisecond)
|
||||||
|
snap = c.snapshot()
|
||||||
|
assert.Equal(t, snap.Totals.RequestCount, uint64(1))
|
||||||
|
assert.Equal(t, snap.RecentRequests[0].Method, "c")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDurationToMillis(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert.Equal(t, durationToMillis(1500*time.Microsecond), 1.5)
|
||||||
|
assert.Equal(t, durationToMillis(0), 0.0)
|
||||||
|
assert.Equal(t, durationToMillis(-5*time.Second), 0.0)
|
||||||
|
// Sub-microsecond durations retain precision rather than truncating to 0.
|
||||||
|
assert.Equal(t, durationToMillis(500*time.Nanosecond), 0.0005)
|
||||||
|
assert.Equal(t, durationToMillis(1234*time.Nanosecond), 0.001234)
|
||||||
|
}
|
||||||
95
tools/tsgo/internal/api/transport.go
Normal file
95
tools/tsgo/internal/api/transport.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transport is an interface for accepting connections from API clients.
|
||||||
|
type Transport interface {
|
||||||
|
// Accept waits for and returns the next connection.
|
||||||
|
Accept() (io.ReadWriteCloser, error)
|
||||||
|
// Close stops the transport from accepting new connections.
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipeTransport accepts connections on a Unix domain socket or Windows named pipe.
|
||||||
|
type PipeTransport struct {
|
||||||
|
listener net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPipeTransport creates a new transport listening on the given path.
|
||||||
|
// On Unix, this creates a Unix domain socket. On Windows, this creates a named pipe.
|
||||||
|
func NewPipeTransport(path string) (*PipeTransport, error) {
|
||||||
|
listener, err := newPipeListener(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &PipeTransport{listener: listener}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept implements Transport.
|
||||||
|
func (t *PipeTransport) Accept() (io.ReadWriteCloser, error) {
|
||||||
|
return t.listener.Accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements Transport.
|
||||||
|
func (t *PipeTransport) Close() error {
|
||||||
|
return t.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path returns the path of the pipe/socket.
|
||||||
|
func (t *PipeTransport) Path() string {
|
||||||
|
return t.listener.Addr().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdioTransport wraps stdin/stdout as a single connection transport.
|
||||||
|
// It only accepts one connection.
|
||||||
|
type StdioTransport struct {
|
||||||
|
stdin io.ReadCloser
|
||||||
|
stdout io.WriteCloser
|
||||||
|
used bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStdioTransport creates a transport using the given stdin/stdout.
|
||||||
|
func NewStdioTransport(stdin io.ReadCloser, stdout io.WriteCloser) *StdioTransport {
|
||||||
|
return &StdioTransport{
|
||||||
|
stdin: stdin,
|
||||||
|
stdout: stdout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept implements Transport.
|
||||||
|
func (t *StdioTransport) Accept() (io.ReadWriteCloser, error) {
|
||||||
|
if t.used {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
t.used = true
|
||||||
|
return &stdioConn{
|
||||||
|
Reader: t.stdin,
|
||||||
|
Writer: t.stdout,
|
||||||
|
stdin: t.stdin,
|
||||||
|
stdout: t.stdout,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements Transport.
|
||||||
|
func (t *StdioTransport) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type stdioConn struct {
|
||||||
|
io.Reader
|
||||||
|
io.Writer
|
||||||
|
stdin io.ReadCloser
|
||||||
|
stdout io.WriteCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *stdioConn) Close() error {
|
||||||
|
err1 := c.stdin.Close()
|
||||||
|
err2 := c.stdout.Close()
|
||||||
|
if err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
return err2
|
||||||
|
}
|
||||||
22
tools/tsgo/internal/api/transport_unix.go
Normal file
22
tools/tsgo/internal/api/transport_unix.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// newPipeListener creates a Unix domain socket listener.
|
||||||
|
func newPipeListener(path string) (net.Listener, error) {
|
||||||
|
// Remove any existing socket file
|
||||||
|
_ = os.Remove(path) //nolint:forbidigo
|
||||||
|
return net.Listen("unix", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePipePath returns a platform-appropriate pipe path for the given name.
|
||||||
|
func GeneratePipePath(name string) string {
|
||||||
|
//nolint:forbidigo
|
||||||
|
return path.Join(os.TempDir(), name)
|
||||||
|
}
|
||||||
19
tools/tsgo/internal/api/transport_windows.go
Normal file
19
tools/tsgo/internal/api/transport_windows.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio"
|
||||||
|
)
|
||||||
|
|
||||||
|
// newPipeListener creates a Windows named pipe listener.
|
||||||
|
func newPipeListener(path string) (net.Listener, error) {
|
||||||
|
return winio.ListenPipe(path, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePipePath returns a platform-appropriate pipe path for the given name.
|
||||||
|
func GeneratePipePath(name string) string {
|
||||||
|
return `\\.\pipe\` + name
|
||||||
|
}
|
||||||
3059
tools/tsgo/internal/ast/ast.go
Normal file
3059
tools/tsgo/internal/ast/ast.go
Normal file
File diff suppressed because it is too large
Load Diff
10047
tools/tsgo/internal/ast/ast_generated.go
Normal file
10047
tools/tsgo/internal/ast/ast_generated.go
Normal file
File diff suppressed because it is too large
Load Diff
36
tools/tsgo/internal/ast/checkflags.go
Normal file
36
tools/tsgo/internal/ast/checkflags.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
// CheckFlags
|
||||||
|
|
||||||
|
type CheckFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
CheckFlagsNone CheckFlags = 0
|
||||||
|
CheckFlagsInstantiated CheckFlags = 1 << 0 // Instantiated symbol
|
||||||
|
CheckFlagsSyntheticProperty CheckFlags = 1 << 1 // Property in union or intersection type
|
||||||
|
CheckFlagsSyntheticMethod CheckFlags = 1 << 2 // Method in union or intersection type
|
||||||
|
CheckFlagsReadonly CheckFlags = 1 << 3 // Readonly transient symbol
|
||||||
|
CheckFlagsReadPartial CheckFlags = 1 << 4 // Synthetic property present in some but not all constituents
|
||||||
|
CheckFlagsWritePartial CheckFlags = 1 << 5 // Synthetic property present in some but only satisfied by an index signature in others
|
||||||
|
CheckFlagsHasNonUniformType CheckFlags = 1 << 6 // Synthetic property with non-uniform type in constituents
|
||||||
|
CheckFlagsHasLiteralType CheckFlags = 1 << 7 // Synthetic property with at least one literal type in constituents
|
||||||
|
CheckFlagsContainsPublic CheckFlags = 1 << 8 // Synthetic property with public constituent(s)
|
||||||
|
CheckFlagsContainsProtected CheckFlags = 1 << 9 // Synthetic property with protected constituent(s)
|
||||||
|
CheckFlagsContainsPrivate CheckFlags = 1 << 10 // Synthetic property with private constituent(s)
|
||||||
|
CheckFlagsContainsStatic CheckFlags = 1 << 11 // Synthetic property with static constituent(s)
|
||||||
|
CheckFlagsLate CheckFlags = 1 << 12 // Late-bound symbol for a computed property with a dynamic name
|
||||||
|
CheckFlagsReverseMapped CheckFlags = 1 << 13 // Property of reverse-inferred homomorphic mapped type
|
||||||
|
CheckFlagsOptionalParameter CheckFlags = 1 << 14 // Optional parameter
|
||||||
|
CheckFlagsRestParameter CheckFlags = 1 << 15 // Rest parameter
|
||||||
|
CheckFlagsDeferredType CheckFlags = 1 << 16 // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType`
|
||||||
|
CheckFlagsHasNeverType CheckFlags = 1 << 17 // Synthetic property with at least one never type in constituents
|
||||||
|
CheckFlagsMapped CheckFlags = 1 << 18 // Property of mapped type
|
||||||
|
CheckFlagsStripOptional CheckFlags = 1 << 19 // Strip optionality in mapped property
|
||||||
|
CheckFlagsUnresolved CheckFlags = 1 << 20 // Unresolved type alias symbol
|
||||||
|
CheckFlagsIsDiscriminantComputed CheckFlags = 1 << 21 // IsDiscriminant flags has been computed
|
||||||
|
CheckFlagsIsDiscriminant CheckFlags = 1 << 22 // Discriminant property
|
||||||
|
CheckFlagsIndexSymbol CheckFlags = 1 << 23 // Synthetic property created from index signature
|
||||||
|
CheckFlagsSynthetic = CheckFlagsSyntheticProperty | CheckFlagsSyntheticMethod
|
||||||
|
CheckFlagsNonUniformAndLiteral = CheckFlagsHasNonUniformType | CheckFlagsHasLiteralType
|
||||||
|
CheckFlagsPartial = CheckFlagsReadPartial | CheckFlagsWritePartial
|
||||||
|
)
|
||||||
86
tools/tsgo/internal/ast/deepclone.go
Normal file
86
tools/tsgo/internal/ast/deepclone.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import "github.com/microsoft/typescript-go/internal/core"
|
||||||
|
|
||||||
|
// Ideally, this would get cached on the node factory so there's only ever one set of closures made per factory
|
||||||
|
func getDeepCloneVisitor(f *NodeFactory, syntheticLocation bool) *NodeVisitor {
|
||||||
|
var visitor *NodeVisitor
|
||||||
|
visitor = NewNodeVisitor(
|
||||||
|
func(node *Node) *Node {
|
||||||
|
visited := visitor.VisitEachChild(node)
|
||||||
|
if visited != node {
|
||||||
|
if syntheticLocation {
|
||||||
|
visited.Loc = core.NewTextRange(-1, -1)
|
||||||
|
}
|
||||||
|
return visited
|
||||||
|
}
|
||||||
|
c := node.Clone(f) // forcibly clone leaf nodes, which will then cascade new nodes/arrays upwards via `update` calls
|
||||||
|
// In strada, `factory.cloneNode` was dynamic and did _not_ clone positions for any "special cases", meanwhile
|
||||||
|
// Node.Clone in corsa reliably uses `Update` calls for all nodes and so copies locations by default.
|
||||||
|
// Deep clones are done to copy a node across files, so here, we explicitly make the location range synthetic on all cloned nodes
|
||||||
|
if syntheticLocation {
|
||||||
|
c.Loc = core.NewTextRange(-1, -1)
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
f,
|
||||||
|
NodeVisitorHooks{
|
||||||
|
VisitNodes: func(nodes *NodeList, v *NodeVisitor) *NodeList {
|
||||||
|
if nodes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
visited := v.VisitNodes(nodes)
|
||||||
|
var newList *NodeList
|
||||||
|
if visited != nodes {
|
||||||
|
newList = visited
|
||||||
|
} else {
|
||||||
|
newList = nodes.Clone(v.Factory)
|
||||||
|
}
|
||||||
|
if syntheticLocation {
|
||||||
|
newList.Loc = core.NewTextRange(-1, -1)
|
||||||
|
if nodes.HasTrailingComma() {
|
||||||
|
newList.Nodes[len(newList.Nodes)-1].Loc = core.NewTextRange(-2, -2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newList
|
||||||
|
},
|
||||||
|
VisitModifiers: func(nodes *ModifierList, v *NodeVisitor) *ModifierList {
|
||||||
|
if nodes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
visited := v.VisitModifiers(nodes)
|
||||||
|
var newList *ModifierList
|
||||||
|
if visited != nodes {
|
||||||
|
newList = visited
|
||||||
|
} else {
|
||||||
|
newList = nodes.Clone(v.Factory)
|
||||||
|
}
|
||||||
|
if syntheticLocation {
|
||||||
|
newList.Loc = core.NewTextRange(-1, -1)
|
||||||
|
if nodes.HasTrailingComma() {
|
||||||
|
newList.Nodes[len(newList.Nodes)-1].Loc = core.NewTextRange(-2, -2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newList
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return visitor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *NodeFactory) DeepCloneNode(node *Node) *Node {
|
||||||
|
return getDeepCloneVisitor(f, true /*syntheticLocation*/).VisitNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *NodeFactory) DeepCloneReparse(node *Node) *Node {
|
||||||
|
if node != nil {
|
||||||
|
node = getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitNode(node)
|
||||||
|
SetParentInChildren(node)
|
||||||
|
node.Flags |= NodeFlagsReparsed
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *NodeFactory) DeepCloneReparseModifiers(modifiers *ModifierList) *ModifierList {
|
||||||
|
return getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitModifiers(modifiers)
|
||||||
|
}
|
||||||
599
tools/tsgo/internal/ast/deepclone_test.go
Normal file
599
tools/tsgo/internal/ast/deepclone_test.go
Normal file
@@ -0,0 +1,599 @@
|
|||||||
|
package ast_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/parsetestutil"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodeComparisonWorkItem struct {
|
||||||
|
original *ast.Node
|
||||||
|
copy *ast.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChildren(node *ast.Node) []*ast.Node {
|
||||||
|
children := []*ast.Node{}
|
||||||
|
node.VisitEachChild(ast.NewNodeVisitor(func(node *ast.Node) *ast.Node {
|
||||||
|
children = append(children, node)
|
||||||
|
return node
|
||||||
|
}, nil, ast.NodeVisitorHooks{}))
|
||||||
|
return children
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeepCloneNodeSanityCheck(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
data := []struct {
|
||||||
|
title string
|
||||||
|
input string
|
||||||
|
jsx bool
|
||||||
|
}{
|
||||||
|
{title: "StringLiteral#1", input: `;"test"`},
|
||||||
|
{title: "StringLiteral#2", input: `;'test'`},
|
||||||
|
{title: "NumericLiteral", input: `0`},
|
||||||
|
{title: "BigIntLiteral", input: `0n`},
|
||||||
|
{title: "BooleanLiteral#1", input: `true`},
|
||||||
|
{title: "BooleanLiteral#2", input: `false`},
|
||||||
|
{title: "NoSubstitutionTemplateLiteral", input: "``"},
|
||||||
|
{title: "RegularExpressionLiteral#1", input: `/a/`},
|
||||||
|
{title: "RegularExpressionLiteral#2", input: `/a/g`},
|
||||||
|
{title: "NullLiteral", input: `null`},
|
||||||
|
{title: "ThisExpression", input: `this`},
|
||||||
|
{title: "SuperExpression", input: `super()`},
|
||||||
|
{title: "ImportExpression", input: `import()`},
|
||||||
|
{title: "PropertyAccess#1", input: `a.b`},
|
||||||
|
{title: "PropertyAccess#2", input: `a.#b`},
|
||||||
|
{title: "PropertyAccess#3", input: `a?.b`},
|
||||||
|
{title: "PropertyAccess#4", input: `a?.b.c`},
|
||||||
|
{title: "PropertyAccess#5", input: `1..b`},
|
||||||
|
{title: "PropertyAccess#6", input: `1.0.b`},
|
||||||
|
{title: "PropertyAccess#7", input: `0x1.b`},
|
||||||
|
{title: "PropertyAccess#8", input: `0b1.b`},
|
||||||
|
{title: "PropertyAccess#9", input: `0o1.b`},
|
||||||
|
{title: "PropertyAccess#10", input: `10e1.b`},
|
||||||
|
{title: "PropertyAccess#11", input: `10E1.b`},
|
||||||
|
{title: "ElementAccess#1", input: `a[b]`},
|
||||||
|
{title: "ElementAccess#2", input: `a?.[b]`},
|
||||||
|
{title: "ElementAccess#3", input: `a?.[b].c`},
|
||||||
|
{title: "CallExpression#1", input: `a()`},
|
||||||
|
{title: "CallExpression#2", input: `a<T>()`},
|
||||||
|
{title: "CallExpression#3", input: `a(b)`},
|
||||||
|
{title: "CallExpression#4", input: `a<T>(b)`},
|
||||||
|
{title: "CallExpression#5", input: `a(b).c`},
|
||||||
|
{title: "CallExpression#6", input: `a<T>(b).c`},
|
||||||
|
{title: "CallExpression#7", input: `a?.(b)`},
|
||||||
|
{title: "CallExpression#8", input: `a?.<T>(b)`},
|
||||||
|
{title: "CallExpression#9", input: `a?.(b).c`},
|
||||||
|
{title: "CallExpression#10", input: `a?.<T>(b).c`},
|
||||||
|
{title: "CallExpression#11", input: `a<T, U>()`},
|
||||||
|
{title: "CallExpression#12", input: `a<T,>()`},
|
||||||
|
{title: "NewExpression#1", input: `new a`},
|
||||||
|
{title: "NewExpression#2", input: `new a.b`},
|
||||||
|
{title: "NewExpression#3", input: `new a()`},
|
||||||
|
{title: "NewExpression#4", input: `new a.b()`},
|
||||||
|
{title: "NewExpression#5", input: `new a<T>()`},
|
||||||
|
{title: "NewExpression#6", input: `new a.b<T>()`},
|
||||||
|
{title: "NewExpression#7", input: `new a(b)`},
|
||||||
|
{title: "NewExpression#8", input: `new a.b(c)`},
|
||||||
|
{title: "NewExpression#9", input: `new a<T>(b)`},
|
||||||
|
{title: "NewExpression#10", input: `new a.b<T>(c)`},
|
||||||
|
{title: "NewExpression#11", input: `new a(b).c`},
|
||||||
|
{title: "NewExpression#12", input: `new a<T>(b).c`},
|
||||||
|
{title: "TaggedTemplateExpression#1", input: "tag``"},
|
||||||
|
{title: "TaggedTemplateExpression#2", input: "tag<T>``"},
|
||||||
|
{title: "TypeAssertionExpression#1", input: `<T>a`},
|
||||||
|
{title: "FunctionExpression#1", input: `(function(){})`},
|
||||||
|
{title: "FunctionExpression#2", input: `(function f(){})`},
|
||||||
|
{title: "FunctionExpression#3", input: `(function*f(){})`},
|
||||||
|
{title: "FunctionExpression#4", input: `(async function f(){})`},
|
||||||
|
{title: "FunctionExpression#5", input: `(async function*f(){})`},
|
||||||
|
{title: "FunctionExpression#6", input: `(function<T>(){})`},
|
||||||
|
{title: "FunctionExpression#7", input: `(function(a){})`},
|
||||||
|
{title: "FunctionExpression#8", input: `(function():T{})`},
|
||||||
|
{title: "ArrowFunction#1", input: `a=>{}`},
|
||||||
|
{title: "ArrowFunction#2", input: `()=>{}`},
|
||||||
|
{title: "ArrowFunction#3", input: `(a)=>{}`},
|
||||||
|
{title: "ArrowFunction#4", input: `<T>(a)=>{}`},
|
||||||
|
{title: "ArrowFunction#5", input: `async a=>{}`},
|
||||||
|
{title: "ArrowFunction#6", input: `async()=>{}`},
|
||||||
|
{title: "ArrowFunction#7", input: `async<T>()=>{}`},
|
||||||
|
{title: "ArrowFunction#8", input: `():T=>{}`},
|
||||||
|
{title: "ArrowFunction#9", input: `()=>a`},
|
||||||
|
{title: "DeleteExpression", input: `delete a`},
|
||||||
|
{title: "TypeOfExpression", input: `typeof a`},
|
||||||
|
{title: "VoidExpression", input: `void a`},
|
||||||
|
{title: "AwaitExpression", input: `await a`},
|
||||||
|
{title: "PrefixUnaryExpression#1", input: `+a`},
|
||||||
|
{title: "PrefixUnaryExpression#2", input: `++a`},
|
||||||
|
{title: "PrefixUnaryExpression#3", input: `+ +a`},
|
||||||
|
{title: "PrefixUnaryExpression#4", input: `+ ++a`},
|
||||||
|
{title: "PrefixUnaryExpression#5", input: `-a`},
|
||||||
|
{title: "PrefixUnaryExpression#6", input: `--a`},
|
||||||
|
{title: "PrefixUnaryExpression#7", input: `- -a`},
|
||||||
|
{title: "PrefixUnaryExpression#8", input: `- --a`},
|
||||||
|
{title: "PrefixUnaryExpression#9", input: `+-a`},
|
||||||
|
{title: "PrefixUnaryExpression#10", input: `+--a`},
|
||||||
|
{title: "PrefixUnaryExpression#11", input: `-+a`},
|
||||||
|
{title: "PrefixUnaryExpression#12", input: `-++a`},
|
||||||
|
{title: "PrefixUnaryExpression#13", input: `~a`},
|
||||||
|
{title: "PrefixUnaryExpression#14", input: `!a`},
|
||||||
|
{title: "PostfixUnaryExpression#1", input: `a++`},
|
||||||
|
{title: "PostfixUnaryExpression#2", input: `a--`},
|
||||||
|
{title: "BinaryExpression#1", input: `a,b`},
|
||||||
|
{title: "BinaryExpression#2", input: `a+b`},
|
||||||
|
{title: "BinaryExpression#3", input: `a**b`},
|
||||||
|
{title: "BinaryExpression#4", input: `a instanceof b`},
|
||||||
|
{title: "BinaryExpression#5", input: `a in b`},
|
||||||
|
{title: "ConditionalExpression", input: `a?b:c`},
|
||||||
|
{title: "TemplateExpression#1", input: "`a${b}c`"},
|
||||||
|
{title: "TemplateExpression#2", input: "`a${b}c${d}e`"},
|
||||||
|
{title: "YieldExpression#1", input: `(function*() { yield })`},
|
||||||
|
{title: "YieldExpression#2", input: `(function*() { yield a })`},
|
||||||
|
{title: "YieldExpression#3", input: `(function*() { yield*a })`},
|
||||||
|
{title: "SpreadElement", input: `[...a]`},
|
||||||
|
{title: "ClassExpression#1", input: `(class {})`},
|
||||||
|
{title: "ClassExpression#2", input: `(class a {})`},
|
||||||
|
{title: "ClassExpression#3", input: `(class<T>{})`},
|
||||||
|
{title: "ClassExpression#4", input: `(class a<T>{})`},
|
||||||
|
{title: "ClassExpression#5", input: `(class extends b {})`},
|
||||||
|
{title: "ClassExpression#6", input: `(class a extends b {})`},
|
||||||
|
{title: "ClassExpression#7", input: `(class implements b {})`},
|
||||||
|
{title: "ClassExpression#8", input: `(class a implements b {})`},
|
||||||
|
{title: "ClassExpression#9", input: `(class implements b, c {})`},
|
||||||
|
{title: "ClassExpression#10", input: `(class a implements b, c {})`},
|
||||||
|
{title: "ClassExpression#11", input: `(class extends b implements c, d {})`},
|
||||||
|
{title: "ClassExpression#12", input: `(class a extends b implements c, d {})`},
|
||||||
|
{title: "ClassExpression#13", input: `(@a class {})`},
|
||||||
|
{title: "OmittedExpression", input: `[,]`},
|
||||||
|
{title: "ExpressionWithTypeArguments", input: `a<T>`},
|
||||||
|
{title: "AsExpression", input: `a as T`},
|
||||||
|
{title: "SatisfiesExpression", input: `a satisfies T`},
|
||||||
|
{title: "NonNullExpression", input: `a!`},
|
||||||
|
{title: "MetaProperty#1", input: `new.target`},
|
||||||
|
{title: "MetaProperty#2", input: `import.meta`},
|
||||||
|
{title: "ArrayLiteralExpression#1", input: `[]`},
|
||||||
|
{title: "ArrayLiteralExpression#2", input: `[a]`},
|
||||||
|
{title: "ArrayLiteralExpression#3", input: `[a,]`},
|
||||||
|
{title: "ArrayLiteralExpression#4", input: `[,a]`},
|
||||||
|
{title: "ArrayLiteralExpression#5", input: `[...a]`},
|
||||||
|
{title: "ObjectLiteralExpression#1", input: `({})`},
|
||||||
|
{title: "ObjectLiteralExpression#2", input: `({a,})`},
|
||||||
|
{title: "ShorthandPropertyAssignment", input: `({a})`},
|
||||||
|
{title: "PropertyAssignment", input: `({a:b})`},
|
||||||
|
{title: "SpreadAssignment", input: `({...a})`},
|
||||||
|
{title: "Block", input: `{}`},
|
||||||
|
{title: "VariableStatement#1", input: `var a`},
|
||||||
|
{title: "VariableStatement#2", input: `let a`},
|
||||||
|
{title: "VariableStatement#3", input: `const a = b`},
|
||||||
|
{title: "VariableStatement#4", input: `using a = b`},
|
||||||
|
{title: "VariableStatement#5", input: `await using a = b`},
|
||||||
|
{title: "EmptyStatement", input: `;`},
|
||||||
|
{title: "IfStatement#1", input: `if(a);`},
|
||||||
|
{title: "IfStatement#2", input: `if(a);else;`},
|
||||||
|
{title: "IfStatement#3", input: `if(a);else{}`},
|
||||||
|
{title: "IfStatement#4", input: `if(a);else if(b);`},
|
||||||
|
{title: "IfStatement#5", input: `if(a);else if(b) {}`},
|
||||||
|
{title: "IfStatement#6", input: `if(a) {}`},
|
||||||
|
{title: "IfStatement#7", input: `if(a) {} else;`},
|
||||||
|
{title: "IfStatement#8", input: `if(a) {} else {}`},
|
||||||
|
{title: "IfStatement#9", input: `if(a) {} else if(b);`},
|
||||||
|
{title: "IfStatement#10", input: `if(a) {} else if(b){}`},
|
||||||
|
{title: "DoStatement#1", input: `do;while(a);`},
|
||||||
|
{title: "DoStatement#2", input: `do {} while(a);`},
|
||||||
|
{title: "WhileStatement#1", input: `while(a);`},
|
||||||
|
{title: "WhileStatement#2", input: `while(a) {}`},
|
||||||
|
{title: "ForStatement#1", input: `for(;;);`},
|
||||||
|
{title: "ForStatement#2", input: `for(a;;);`},
|
||||||
|
{title: "ForStatement#3", input: `for(var a;;);`},
|
||||||
|
{title: "ForStatement#4", input: `for(;a;);`},
|
||||||
|
{title: "ForStatement#5", input: `for(;;a);`},
|
||||||
|
{title: "ForStatement#6", input: `for(;;){}`},
|
||||||
|
{title: "ForInStatement#1", input: `for(a in b);`},
|
||||||
|
{title: "ForInStatement#2", input: `for(var a in b);`},
|
||||||
|
{title: "ForInStatement#3", input: `for(a in b){}`},
|
||||||
|
{title: "ForOfStatement#1", input: `for(a of b);`},
|
||||||
|
{title: "ForOfStatement#2", input: `for(var a of b);`},
|
||||||
|
{title: "ForOfStatement#3", input: `for(a of b){}`},
|
||||||
|
{title: "ForOfStatement#4", input: `for await(a of b);`},
|
||||||
|
{title: "ForOfStatement#5", input: `for await(var a of b);`},
|
||||||
|
{title: "ForOfStatement#6", input: `for await(a of b){}`},
|
||||||
|
{title: "ContinueStatement#1", input: `continue`},
|
||||||
|
{title: "ContinueStatement#2", input: `continue a`},
|
||||||
|
{title: "BreakStatement#1", input: `break`},
|
||||||
|
{title: "BreakStatement#2", input: `break a`},
|
||||||
|
{title: "ReturnStatement#1", input: `return`},
|
||||||
|
{title: "ReturnStatement#2", input: `return a`},
|
||||||
|
{title: "WithStatement#1", input: `with(a);`},
|
||||||
|
{title: "WithStatement#2", input: `with(a){}`},
|
||||||
|
{title: "SwitchStatement", input: `switch (a) {}`},
|
||||||
|
{title: "CaseClause#1", input: `switch (a) {case b:}`},
|
||||||
|
{title: "CaseClause#2", input: `switch (a) {case b:;}`},
|
||||||
|
{title: "DefaultClause#1", input: `switch (a) {default:}`},
|
||||||
|
{title: "DefaultClause#2", input: `switch (a) {default:;}`},
|
||||||
|
{title: "LabeledStatement", input: `a:;`},
|
||||||
|
{title: "ThrowStatement", input: `throw a`},
|
||||||
|
{title: "TryStatement#1", input: `try {} catch {}`},
|
||||||
|
{title: "TryStatement#2", input: `try {} finally {}`},
|
||||||
|
{title: "TryStatement#3", input: `try {} catch {} finally {}`},
|
||||||
|
{title: "DebuggerStatement", input: `debugger`},
|
||||||
|
{title: "FunctionDeclaration#1", input: `export default function(){}`},
|
||||||
|
{title: "FunctionDeclaration#2", input: `function f(){}`},
|
||||||
|
{title: "FunctionDeclaration#3", input: `function*f(){}`},
|
||||||
|
{title: "FunctionDeclaration#4", input: `async function f(){}`},
|
||||||
|
{title: "FunctionDeclaration#5", input: `async function*f(){}`},
|
||||||
|
{title: "FunctionDeclaration#6", input: `function f<T>(){}`},
|
||||||
|
{title: "FunctionDeclaration#7", input: `function f(a){}`},
|
||||||
|
{title: "FunctionDeclaration#8", input: `function f():T{}`},
|
||||||
|
{title: "FunctionDeclaration#9", input: `function f();`},
|
||||||
|
{title: "ClassDeclaration#1", input: `class a {}`},
|
||||||
|
{title: "ClassDeclaration#2", input: `class a<T>{}`},
|
||||||
|
{title: "ClassDeclaration#3", input: `class a extends b {}`},
|
||||||
|
{title: "ClassDeclaration#4", input: `class a implements b {}`},
|
||||||
|
{title: "ClassDeclaration#5", input: `class a implements b, c {}`},
|
||||||
|
{title: "ClassDeclaration#6", input: `class a extends b implements c, d {}`},
|
||||||
|
{title: "ClassDeclaration#7", input: `export default class {}`},
|
||||||
|
{title: "ClassDeclaration#8", input: `export default class<T>{}`},
|
||||||
|
{title: "ClassDeclaration#9", input: `export default class extends b {}`},
|
||||||
|
{title: "ClassDeclaration#10", input: `export default class implements b {}`},
|
||||||
|
{title: "ClassDeclaration#11", input: `export default class implements b, c {}`},
|
||||||
|
{title: "ClassDeclaration#12", input: `export default class extends b implements c, d {}`},
|
||||||
|
{title: "ClassDeclaration#13", input: `@a class b {}`},
|
||||||
|
{title: "ClassDeclaration#14", input: `@a export class b {}`},
|
||||||
|
{title: "ClassDeclaration#15", input: `export @a class b {}`},
|
||||||
|
{title: "InterfaceDeclaration#1", input: `interface a {}`},
|
||||||
|
{title: "InterfaceDeclaration#2", input: `interface a<T>{}`},
|
||||||
|
{title: "InterfaceDeclaration#3", input: `interface a extends b {}`},
|
||||||
|
{title: "InterfaceDeclaration#4", input: `interface a extends b, c {}`},
|
||||||
|
{title: "TypeAliasDeclaration#1", input: `type a = b`},
|
||||||
|
{title: "TypeAliasDeclaration#2", input: `type a<T> = b`},
|
||||||
|
{title: "EnumDeclaration#1", input: `enum a{}`},
|
||||||
|
{title: "EnumDeclaration#2", input: `enum a{b}`},
|
||||||
|
{title: "EnumDeclaration#3", input: `enum a{b=c}`},
|
||||||
|
{title: "ModuleDeclaration#1", input: `module a{}`},
|
||||||
|
{title: "ModuleDeclaration#2", input: `module a.b{}`},
|
||||||
|
{title: "ModuleDeclaration#3", input: `module "a";`},
|
||||||
|
{title: "ModuleDeclaration#4", input: `module "a"{}`},
|
||||||
|
{title: "ModuleDeclaration#5", input: `namespace a{}`},
|
||||||
|
{title: "ModuleDeclaration#6", input: `namespace a.b{}`},
|
||||||
|
{title: "ModuleDeclaration#7", input: `global;`},
|
||||||
|
{title: "ModuleDeclaration#8", input: `global{}`},
|
||||||
|
{title: "ImportEqualsDeclaration#1", input: `import a = b`},
|
||||||
|
{title: "ImportEqualsDeclaration#2", input: `import a = b.c`},
|
||||||
|
{title: "ImportEqualsDeclaration#3", input: `import a = require("b")`},
|
||||||
|
{title: "ImportEqualsDeclaration#4", input: `export import a = b`},
|
||||||
|
{title: "ImportEqualsDeclaration#5", input: `export import a = require("b")`},
|
||||||
|
{title: "ImportEqualsDeclaration#6", input: `import type a = b`},
|
||||||
|
{title: "ImportEqualsDeclaration#7", input: `import type a = b.c`},
|
||||||
|
{title: "ImportEqualsDeclaration#8", input: `import type a = require("b")`},
|
||||||
|
{title: "ImportDeclaration#1", input: `import "a"`},
|
||||||
|
{title: "ImportDeclaration#2", input: `import a from "b"`},
|
||||||
|
{title: "ImportDeclaration#3", input: `import type a from "b"`},
|
||||||
|
{title: "ImportDeclaration#4", input: `import * as a from "b"`},
|
||||||
|
{title: "ImportDeclaration#5", input: `import type * as a from "b"`},
|
||||||
|
{title: "ImportDeclaration#6", input: `import {} from "b"`},
|
||||||
|
{title: "ImportDeclaration#7", input: `import type {} from "b"`},
|
||||||
|
{title: "ImportDeclaration#8", input: `import { a } from "b"`},
|
||||||
|
{title: "ImportDeclaration#9", input: `import type { a } from "b"`},
|
||||||
|
{title: "ImportDeclaration#8", input: `import { a as b } from "c"`},
|
||||||
|
{title: "ImportDeclaration#9", input: `import type { a as b } from "c"`},
|
||||||
|
{title: "ImportDeclaration#10", input: `import { "a" as b } from "c"`},
|
||||||
|
{title: "ImportDeclaration#11", input: `import type { "a" as b } from "c"`},
|
||||||
|
{title: "ImportDeclaration#12", input: `import a, {} from "b"`},
|
||||||
|
{title: "ImportDeclaration#13", input: `import a, * as b from "c"`},
|
||||||
|
{title: "ImportDeclaration#14", input: `import {} from "a" with {}`},
|
||||||
|
{title: "ImportDeclaration#15", input: `import {} from "a" with { b: "c" }`},
|
||||||
|
{title: "ImportDeclaration#16", input: `import {} from "a" with { "b": "c" }`},
|
||||||
|
{title: "ExportAssignment#1", input: `export = a`},
|
||||||
|
{title: "ExportAssignment#2", input: `export default a`},
|
||||||
|
{title: "NamespaceExportDeclaration", input: `export as namespace a`},
|
||||||
|
{title: "ExportDeclaration#1", input: `export * from "a"`},
|
||||||
|
{title: "ExportDeclaration#2", input: `export type * from "a"`},
|
||||||
|
{title: "ExportDeclaration#3", input: `export * as a from "b"`},
|
||||||
|
{title: "ExportDeclaration#4", input: `export type * as a from "b"`},
|
||||||
|
{title: "ExportDeclaration#5", input: `export { } from "a"`},
|
||||||
|
{title: "ExportDeclaration#6", input: `export type { } from "a"`},
|
||||||
|
{title: "ExportDeclaration#7", input: `export { a } from "b"`},
|
||||||
|
{title: "ExportDeclaration#8", input: `export { type a } from "b"`},
|
||||||
|
{title: "ExportDeclaration#9", input: `export type { a } from "b"`},
|
||||||
|
{title: "ExportDeclaration#10", input: `export { a as b } from "c"`},
|
||||||
|
{title: "ExportDeclaration#11", input: `export { type a as b } from "c"`},
|
||||||
|
{title: "ExportDeclaration#12", input: `export type { a as b } from "c"`},
|
||||||
|
{title: "ExportDeclaration#13", input: `export { a as "b" } from "c"`},
|
||||||
|
{title: "ExportDeclaration#14", input: `export { type a as "b" } from "c"`},
|
||||||
|
{title: "ExportDeclaration#15", input: `export type { a as "b" } from "c"`},
|
||||||
|
{title: "ExportDeclaration#16", input: `export { "a" } from "b"`},
|
||||||
|
{title: "ExportDeclaration#17", input: `export { type "a" } from "b"`},
|
||||||
|
{title: "ExportDeclaration#18", input: `export type { "a" } from "b"`},
|
||||||
|
{title: "ExportDeclaration#19", input: `export { "a" as b } from "c"`},
|
||||||
|
{title: "ExportDeclaration#20", input: `export { type "a" as b } from "c"`},
|
||||||
|
{title: "ExportDeclaration#21", input: `export type { "a" as b } from "c"`},
|
||||||
|
{title: "ExportDeclaration#22", input: `export { "a" as "b" } from "c"`},
|
||||||
|
{title: "ExportDeclaration#23", input: `export { type "a" as "b" } from "c"`},
|
||||||
|
{title: "ExportDeclaration#24", input: `export type { "a" as "b" } from "c"`},
|
||||||
|
{title: "ExportDeclaration#25", input: `export { }`},
|
||||||
|
{title: "ExportDeclaration#26", input: `export type { }`},
|
||||||
|
{title: "ExportDeclaration#27", input: `export { a }`},
|
||||||
|
{title: "ExportDeclaration#28", input: `export { type a }`},
|
||||||
|
{title: "ExportDeclaration#29", input: `export type { a }`},
|
||||||
|
{title: "ExportDeclaration#30", input: `export { a as b }`},
|
||||||
|
{title: "ExportDeclaration#31", input: `export { type a as b }`},
|
||||||
|
{title: "ExportDeclaration#32", input: `export type { a as b }`},
|
||||||
|
{title: "ExportDeclaration#33", input: `export { a as "b" }`},
|
||||||
|
{title: "ExportDeclaration#34", input: `export { type a as "b" }`},
|
||||||
|
{title: "ExportDeclaration#35", input: `export type { a as "b" }`},
|
||||||
|
{title: "ExportDeclaration#36", input: `export {} from "a" with {}`},
|
||||||
|
{title: "ExportDeclaration#37", input: `export {} from "a" with { b: "c" }`},
|
||||||
|
{title: "ExportDeclaration#38", input: `export {} from "a" with { "b": "c" }`},
|
||||||
|
{title: "KeywordTypeNode#1", input: `type T = any`},
|
||||||
|
{title: "KeywordTypeNode#2", input: `type T = unknown`},
|
||||||
|
{title: "KeywordTypeNode#3", input: `type T = never`},
|
||||||
|
{title: "KeywordTypeNode#4", input: `type T = void`},
|
||||||
|
{title: "KeywordTypeNode#5", input: `type T = undefined`},
|
||||||
|
{title: "KeywordTypeNode#6", input: `type T = null`},
|
||||||
|
{title: "KeywordTypeNode#7", input: `type T = object`},
|
||||||
|
{title: "KeywordTypeNode#8", input: `type T = string`},
|
||||||
|
{title: "KeywordTypeNode#9", input: `type T = symbol`},
|
||||||
|
{title: "KeywordTypeNode#10", input: `type T = number`},
|
||||||
|
{title: "KeywordTypeNode#11", input: `type T = bigint`},
|
||||||
|
{title: "KeywordTypeNode#12", input: `type T = boolean`},
|
||||||
|
{title: "KeywordTypeNode#13", input: `type T = intrinsic`},
|
||||||
|
{title: "TypePredicateNode#1", input: `function f(): asserts a`},
|
||||||
|
{title: "TypePredicateNode#2", input: `function f(): asserts a is b`},
|
||||||
|
{title: "TypePredicateNode#3", input: `function f(): asserts this`},
|
||||||
|
{title: "TypePredicateNode#4", input: `function f(): asserts this is b`},
|
||||||
|
{title: "TypeReferenceNode#1", input: `type T = a`},
|
||||||
|
{title: "TypeReferenceNode#2", input: `type T = a.b`},
|
||||||
|
{title: "TypeReferenceNode#3", input: `type T = a<U>`},
|
||||||
|
{title: "TypeReferenceNode#4", input: `type T = a.b<U>`},
|
||||||
|
{title: "FunctionTypeNode#1", input: `type T = () => a`},
|
||||||
|
{title: "FunctionTypeNode#2", input: `type T = <T>() => a`},
|
||||||
|
{title: "FunctionTypeNode#3", input: `type T = (a) => b`},
|
||||||
|
{title: "ConstructorTypeNode#1", input: `type T = new () => a`},
|
||||||
|
{title: "ConstructorTypeNode#2", input: `type T = new <T>() => a`},
|
||||||
|
{title: "ConstructorTypeNode#3", input: `type T = new (a) => b`},
|
||||||
|
{title: "ConstructorTypeNode#4", input: `type T = abstract new () => a`},
|
||||||
|
{title: "TypeQueryNode#1", input: `type T = typeof a`},
|
||||||
|
{title: "TypeQueryNode#2", input: `type T = typeof a.b`},
|
||||||
|
{title: "TypeQueryNode#3", input: `type T = typeof a<U>`},
|
||||||
|
{title: "TypeLiteralNode#1", input: `type T = {}`},
|
||||||
|
{title: "TypeLiteralNode#2", input: `type T = {a}`},
|
||||||
|
{title: "ArrayTypeNode", input: `type T = a[]`},
|
||||||
|
{title: "TupleTypeNode#1", input: `type T = []`},
|
||||||
|
{title: "TupleTypeNode#2", input: `type T = [a]`},
|
||||||
|
{title: "TupleTypeNode#3", input: `type T = [a,]`},
|
||||||
|
{title: "RestTypeNode", input: `type T = [...a]`},
|
||||||
|
{title: "OptionalTypeNode", input: `type T = [a?]`},
|
||||||
|
{title: "NamedTupleMember#1", input: `type T = [a: b]`},
|
||||||
|
{title: "NamedTupleMember#2", input: `type T = [a?: b]`},
|
||||||
|
{title: "NamedTupleMember#3", input: `type T = [...a: b]`},
|
||||||
|
{title: "UnionTypeNode#1", input: `type T = a | b`},
|
||||||
|
{title: "UnionTypeNode#2", input: `type T = a | b | c`},
|
||||||
|
{title: "UnionTypeNode#3", input: `type T = | a | b`},
|
||||||
|
{title: "IntersectionTypeNode#1", input: `type T = a & b`},
|
||||||
|
{title: "IntersectionTypeNode#2", input: `type T = a & b & c`},
|
||||||
|
{title: "IntersectionTypeNode#3", input: `type T = & a & b`},
|
||||||
|
{title: "ConditionalTypeNode", input: `type T = a extends b ? c : d`},
|
||||||
|
{title: "InferTypeNode#1", input: `type T = a extends infer b ? c : d`},
|
||||||
|
{title: "InferTypeNode#2", input: `type T = a extends infer b extends c ? d : e`},
|
||||||
|
{title: "ParenthesizedTypeNode", input: `type T = (U)`},
|
||||||
|
{title: "ThisTypeNode", input: `type T = this`},
|
||||||
|
{title: "TypeOperatorNode#1", input: `type T = keyof U`},
|
||||||
|
{title: "TypeOperatorNode#2", input: `type T = readonly U[]`},
|
||||||
|
{title: "TypeOperatorNode#3", input: `type T = unique symbol`},
|
||||||
|
{title: "IndexedAccessTypeNode", input: `type T = a[b]`},
|
||||||
|
{title: "MappedTypeNode#1", input: `type T = { [a in b]: c }`},
|
||||||
|
{title: "MappedTypeNode#2", input: `type T = { [a in b as c]: d }`},
|
||||||
|
{title: "MappedTypeNode#3", input: `type T = { readonly [a in b]: c }`},
|
||||||
|
{title: "MappedTypeNode#4", input: `type T = { +readonly [a in b]: c }`},
|
||||||
|
{title: "MappedTypeNode#5", input: `type T = { -readonly [a in b]: c }`},
|
||||||
|
{title: "MappedTypeNode#6", input: `type T = { [a in b]?: c }`},
|
||||||
|
{title: "MappedTypeNode#7", input: `type T = { [a in b]+?: c }`},
|
||||||
|
{title: "MappedTypeNode#8", input: `type T = { [a in b]-?: c }`},
|
||||||
|
{title: "MappedTypeNode#9", input: `type T = { [a in b]: c; d }`},
|
||||||
|
{title: "LiteralTypeNode#1", input: `type T = null`},
|
||||||
|
{title: "LiteralTypeNode#2", input: `type T = true`},
|
||||||
|
{title: "LiteralTypeNode#3", input: `type T = false`},
|
||||||
|
{title: "LiteralTypeNode#4", input: `type T = ""`},
|
||||||
|
{title: "LiteralTypeNode#5", input: "type T = ''"},
|
||||||
|
{title: "LiteralTypeNode#6", input: "type T = ``"},
|
||||||
|
{title: "LiteralTypeNode#7", input: `type T = 0`},
|
||||||
|
{title: "LiteralTypeNode#8", input: `type T = 0n`},
|
||||||
|
{title: "LiteralTypeNode#9", input: `type T = -0`},
|
||||||
|
{title: "LiteralTypeNode#10", input: `type T = -0n`},
|
||||||
|
{title: "TemplateTypeNode#1", input: "type T = `a${b}c`"},
|
||||||
|
{title: "TemplateTypeNode#2", input: "type T = `a${b}c${d}e`"},
|
||||||
|
{title: "ImportTypeNode#1", input: `type T = import(a)`},
|
||||||
|
{title: "ImportTypeNode#2", input: `type T = import(a).b`},
|
||||||
|
{title: "ImportTypeNode#3", input: `type T = import(a).b<U>`},
|
||||||
|
{title: "ImportTypeNode#4", input: `type T = typeof import(a)`},
|
||||||
|
{title: "ImportTypeNode#5", input: `type T = typeof import(a).b`},
|
||||||
|
{title: "ImportTypeNode#6", input: `type T = import(a, { with: { } })`},
|
||||||
|
{title: "ImportTypeNode#6", input: `type T = import(a, { with: { b: "c" } })`},
|
||||||
|
{title: "ImportTypeNode#7", input: `type T = import(a, { with: { "b": "c" } })`},
|
||||||
|
{title: "PropertySignature#1", input: "interface I {a}"},
|
||||||
|
{title: "PropertySignature#2", input: "interface I {readonly a}"},
|
||||||
|
{title: "PropertySignature#3", input: "interface I {\"a\"}"},
|
||||||
|
{title: "PropertySignature#4", input: "interface I {'a'}"},
|
||||||
|
{title: "PropertySignature#5", input: "interface I {0}"},
|
||||||
|
{title: "PropertySignature#6", input: "interface I {0n}"},
|
||||||
|
{title: "PropertySignature#7", input: "interface I {[a]}"},
|
||||||
|
{title: "PropertySignature#8", input: "interface I {a?}"},
|
||||||
|
{title: "PropertySignature#9", input: "interface I {a: b}"},
|
||||||
|
{title: "MethodSignature#1", input: "interface I {a()}"},
|
||||||
|
{title: "MethodSignature#2", input: "interface I {\"a\"()}"},
|
||||||
|
{title: "MethodSignature#3", input: "interface I {'a'()}"},
|
||||||
|
{title: "MethodSignature#4", input: "interface I {0()}"},
|
||||||
|
{title: "MethodSignature#5", input: "interface I {0n()}"},
|
||||||
|
{title: "MethodSignature#6", input: "interface I {[a]()}"},
|
||||||
|
{title: "MethodSignature#7", input: "interface I {a?()}"},
|
||||||
|
{title: "MethodSignature#8", input: "interface I {a<T>()}"},
|
||||||
|
{title: "MethodSignature#9", input: "interface I {a(): b}"},
|
||||||
|
{title: "MethodSignature#10", input: "interface I {a(b): c}"},
|
||||||
|
{title: "CallSignature#1", input: "interface I {()}"},
|
||||||
|
{title: "CallSignature#2", input: "interface I {():a}"},
|
||||||
|
{title: "CallSignature#3", input: "interface I {(p)}"},
|
||||||
|
{title: "CallSignature#4", input: "interface I {<T>()}"},
|
||||||
|
{title: "ConstructSignature#1", input: "interface I {new ()}"},
|
||||||
|
{title: "ConstructSignature#2", input: "interface I {new ():a}"},
|
||||||
|
{title: "ConstructSignature#3", input: "interface I {new (p)}"},
|
||||||
|
{title: "ConstructSignature#4", input: "interface I {new <T>()}"},
|
||||||
|
{title: "IndexSignatureDeclaration#1", input: "interface I {[a]}"},
|
||||||
|
{title: "IndexSignatureDeclaration#2", input: "interface I {[a: b]}"},
|
||||||
|
{title: "IndexSignatureDeclaration#3", input: "interface I {[a: b]: c}"},
|
||||||
|
{title: "PropertyDeclaration#1", input: "class C {a}"},
|
||||||
|
{title: "PropertyDeclaration#2", input: "class C {readonly a}"},
|
||||||
|
{title: "PropertyDeclaration#3", input: "class C {static a}"},
|
||||||
|
{title: "PropertyDeclaration#4", input: "class C {accessor a}"},
|
||||||
|
{title: "PropertyDeclaration#5", input: "class C {\"a\"}"},
|
||||||
|
{title: "PropertyDeclaration#6", input: "class C {'a'}"},
|
||||||
|
{title: "PropertyDeclaration#7", input: "class C {0}"},
|
||||||
|
{title: "PropertyDeclaration#8", input: "class C {0n}"},
|
||||||
|
{title: "PropertyDeclaration#9", input: "class C {[a]}"},
|
||||||
|
{title: "PropertyDeclaration#10", input: "class C {#a}"},
|
||||||
|
{title: "PropertyDeclaration#11", input: "class C {a?}"},
|
||||||
|
{title: "PropertyDeclaration#12", input: "class C {a!}"},
|
||||||
|
{title: "PropertyDeclaration#13", input: "class C {a: b}"},
|
||||||
|
{title: "PropertyDeclaration#14", input: "class C {a = b}"},
|
||||||
|
{title: "PropertyDeclaration#15", input: "class C {@a b}"},
|
||||||
|
{title: "MethodDeclaration#1", input: "class C {a()}"},
|
||||||
|
{title: "MethodDeclaration#2", input: "class C {\"a\"()}"},
|
||||||
|
{title: "MethodDeclaration#3", input: "class C {'a'()}"},
|
||||||
|
{title: "MethodDeclaration#4", input: "class C {0()}"},
|
||||||
|
{title: "MethodDeclaration#5", input: "class C {0n()}"},
|
||||||
|
{title: "MethodDeclaration#6", input: "class C {[a]()}"},
|
||||||
|
{title: "MethodDeclaration#7", input: "class C {#a()}"},
|
||||||
|
{title: "MethodDeclaration#8", input: "class C {a?()}"},
|
||||||
|
{title: "MethodDeclaration#9", input: "class C {a<T>()}"},
|
||||||
|
{title: "MethodDeclaration#10", input: "class C {a(): b}"},
|
||||||
|
{title: "MethodDeclaration#11", input: "class C {a(b): c}"},
|
||||||
|
{title: "MethodDeclaration#12", input: "class C {a() {} }"},
|
||||||
|
{title: "MethodDeclaration#13", input: "class C {@a b() {} }"},
|
||||||
|
{title: "MethodDeclaration#14", input: "class C {static a() {} }"},
|
||||||
|
{title: "MethodDeclaration#15", input: "class C {async a() {} }"},
|
||||||
|
{title: "GetAccessorDeclaration#1", input: "class C {get a()}"},
|
||||||
|
{title: "GetAccessorDeclaration#2", input: "class C {get \"a\"()}"},
|
||||||
|
{title: "GetAccessorDeclaration#3", input: "class C {get 'a'()}"},
|
||||||
|
{title: "GetAccessorDeclaration#4", input: "class C {get 0()}"},
|
||||||
|
{title: "GetAccessorDeclaration#5", input: "class C {get 0n()}"},
|
||||||
|
{title: "GetAccessorDeclaration#6", input: "class C {get [a]()}"},
|
||||||
|
{title: "GetAccessorDeclaration#7", input: "class C {get #a()}"},
|
||||||
|
{title: "GetAccessorDeclaration#8", input: "class C {get a(): b}"},
|
||||||
|
{title: "GetAccessorDeclaration#9", input: "class C {get a(b): c}"},
|
||||||
|
{title: "GetAccessorDeclaration#10", input: "class C {get a() {} }"},
|
||||||
|
{title: "GetAccessorDeclaration#11", input: "class C {@a get b() {} }"},
|
||||||
|
{title: "GetAccessorDeclaration#12", input: "class C {static get a() {} }"},
|
||||||
|
{title: "SetAccessorDeclaration#1", input: "class C {set a()}"},
|
||||||
|
{title: "SetAccessorDeclaration#2", input: "class C {set \"a\"()}"},
|
||||||
|
{title: "SetAccessorDeclaration#3", input: "class C {set 'a'()}"},
|
||||||
|
{title: "SetAccessorDeclaration#4", input: "class C {set 0()}"},
|
||||||
|
{title: "SetAccessorDeclaration#5", input: "class C {set 0n()}"},
|
||||||
|
{title: "SetAccessorDeclaration#6", input: "class C {set [a]()}"},
|
||||||
|
{title: "SetAccessorDeclaration#7", input: "class C {set #a()}"},
|
||||||
|
{title: "SetAccessorDeclaration#8", input: "class C {set a(): b}"},
|
||||||
|
{title: "SetAccessorDeclaration#9", input: "class C {set a(b): c}"},
|
||||||
|
{title: "SetAccessorDeclaration#10", input: "class C {set a() {} }"},
|
||||||
|
{title: "SetAccessorDeclaration#11", input: "class C {@a set b() {} }"},
|
||||||
|
{title: "SetAccessorDeclaration#12", input: "class C {static set a() {} }"},
|
||||||
|
{title: "ConstructorDeclaration#1", input: "class C {constructor()}"},
|
||||||
|
{title: "ConstructorDeclaration#2", input: "class C {constructor(): b}"},
|
||||||
|
{title: "ConstructorDeclaration#3", input: "class C {constructor(b): c}"},
|
||||||
|
{title: "ConstructorDeclaration#4", input: "class C {constructor() {} }"},
|
||||||
|
{title: "ConstructorDeclaration#5", input: "class C {@a constructor() {} }"},
|
||||||
|
{title: "ConstructorDeclaration#6", input: "class C {private constructor() {} }"},
|
||||||
|
{title: "ClassStaticBlockDeclaration", input: "class C {static { }}"},
|
||||||
|
{title: "SemicolonClassElement#1", input: "class C {;}"},
|
||||||
|
{title: "ParameterDeclaration#1", input: "function f(a)"},
|
||||||
|
{title: "ParameterDeclaration#2", input: "function f(a: b)"},
|
||||||
|
{title: "ParameterDeclaration#3", input: "function f(a = b)"},
|
||||||
|
{title: "ParameterDeclaration#4", input: "function f(a?)"},
|
||||||
|
{title: "ParameterDeclaration#5", input: "function f(...a)"},
|
||||||
|
{title: "ParameterDeclaration#6", input: "function f(this)"},
|
||||||
|
{title: "ParameterDeclaration#7", input: "function f(a,)"},
|
||||||
|
{title: "ObjectBindingPattern#1", input: "function f({})"},
|
||||||
|
{title: "ObjectBindingPattern#2", input: "function f({a})"},
|
||||||
|
{title: "ObjectBindingPattern#3", input: "function f({a = b})"},
|
||||||
|
{title: "ObjectBindingPattern#4", input: "function f({a: b})"},
|
||||||
|
{title: "ObjectBindingPattern#5", input: "function f({a: b = c})"},
|
||||||
|
{title: "ObjectBindingPattern#6", input: "function f({\"a\": b})"},
|
||||||
|
{title: "ObjectBindingPattern#7", input: "function f({'a': b})"},
|
||||||
|
{title: "ObjectBindingPattern#8", input: "function f({0: b})"},
|
||||||
|
{title: "ObjectBindingPattern#9", input: "function f({[a]: b})"},
|
||||||
|
{title: "ObjectBindingPattern#10", input: "function f({...a})"},
|
||||||
|
{title: "ObjectBindingPattern#11", input: "function f({a: {}})"},
|
||||||
|
{title: "ObjectBindingPattern#12", input: "function f({a: []})"},
|
||||||
|
{title: "ArrayBindingPattern#1", input: "function f([])"},
|
||||||
|
{title: "ArrayBindingPattern#2", input: "function f([,])"},
|
||||||
|
{title: "ArrayBindingPattern#3", input: "function f([a])"},
|
||||||
|
{title: "ArrayBindingPattern#4", input: "function f([a, b])"},
|
||||||
|
{title: "ArrayBindingPattern#5", input: "function f([a, , b])"},
|
||||||
|
{title: "ArrayBindingPattern#6", input: "function f([a = b])"},
|
||||||
|
{title: "ArrayBindingPattern#7", input: "function f([...a])"},
|
||||||
|
{title: "ArrayBindingPattern#8", input: "function f([{}])"},
|
||||||
|
{title: "ArrayBindingPattern#9", input: "function f([[]])"},
|
||||||
|
{title: "TypeParameterDeclaration#1", input: "function f<T>();"},
|
||||||
|
{title: "TypeParameterDeclaration#2", input: "function f<in T>();"},
|
||||||
|
{title: "TypeParameterDeclaration#3", input: "function f<T extends U>();"},
|
||||||
|
{title: "TypeParameterDeclaration#4", input: "function f<T = U>();"},
|
||||||
|
{title: "TypeParameterDeclaration#5", input: "function f<T extends U = V>();"},
|
||||||
|
{title: "TypeParameterDeclaration#6", input: "function f<T, U>();"},
|
||||||
|
{title: "TypeParameterDeclaration#7", input: "function f<T,>();"},
|
||||||
|
{title: "JsxElement1", input: "<a></a>"},
|
||||||
|
{title: "JsxElement2", input: "<this></this>"},
|
||||||
|
{title: "JsxElement3", input: "<a:b></a:b>"},
|
||||||
|
{title: "JsxElement4", input: "<a.b></a.b>"},
|
||||||
|
{title: "JsxElement5", input: "<a<b>></a>"},
|
||||||
|
{title: "JsxElement6", input: "<a b></a>"},
|
||||||
|
{title: "JsxElement7", input: "<a>b</a>"},
|
||||||
|
{title: "JsxElement8", input: "<a>{b}</a>"},
|
||||||
|
{title: "JsxElement9", input: "<a><b></b></a>"},
|
||||||
|
{title: "JsxElement10", input: "<a><b /></a>"},
|
||||||
|
{title: "JsxElement11", input: "<a><></></a>"},
|
||||||
|
{title: "JsxSelfClosingElement1", input: "<a />"},
|
||||||
|
{title: "JsxSelfClosingElement2", input: "<this />"},
|
||||||
|
{title: "JsxSelfClosingElement3", input: "<a:b />"},
|
||||||
|
{title: "JsxSelfClosingElement4", input: "<a.b />"},
|
||||||
|
{title: "JsxSelfClosingElement5", input: "<a<b> />"},
|
||||||
|
{title: "JsxSelfClosingElement6", input: "<a b/>"},
|
||||||
|
{title: "JsxFragment1", input: "<></>"},
|
||||||
|
{title: "JsxFragment2", input: "<>b</>"},
|
||||||
|
{title: "JsxFragment3", input: "<>{b}</>"},
|
||||||
|
{title: "JsxFragment4", input: "<><b></b></>"},
|
||||||
|
{title: "JsxFragment5", input: "<><b /></>"},
|
||||||
|
{title: "JsxFragment6", input: "<><></></>"},
|
||||||
|
{title: "JsxAttribute1", input: "<a b/>"},
|
||||||
|
{title: "JsxAttribute2", input: "<a b:c/>"},
|
||||||
|
{title: "JsxAttribute3", input: "<a b=\"c\"/>"},
|
||||||
|
{title: "JsxAttribute4", input: "<a b='c'/>"},
|
||||||
|
{title: "JsxAttribute5", input: "<a b={c}/>"},
|
||||||
|
{title: "JsxAttribute6", input: "<a b=<c></c>/>"},
|
||||||
|
{title: "JsxAttribute7", input: "<a b=<c />/>"},
|
||||||
|
{title: "JsxAttribute8", input: "<a b=<></>/>"},
|
||||||
|
{title: "JsxSpreadAttribute", input: "<a {...b}/>"},
|
||||||
|
}
|
||||||
|
for _, rec := range data {
|
||||||
|
t.Run("Clone "+rec.title, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
factory := &ast.NodeFactory{}
|
||||||
|
file := parsetestutil.ParseTypeScript(rec.input, false).AsNode()
|
||||||
|
clone := factory.DeepCloneNode(file.AsNode()).AsNode()
|
||||||
|
|
||||||
|
work := []NodeComparisonWorkItem{{file, clone}}
|
||||||
|
|
||||||
|
for len(work) > 0 {
|
||||||
|
nextWork := []NodeComparisonWorkItem{}
|
||||||
|
for _, item := range work {
|
||||||
|
assert.Assert(t, item.original != item.copy)
|
||||||
|
originalChildren := getChildren(item.original)
|
||||||
|
copyChildren := getChildren(item.copy)
|
||||||
|
assert.Equal(t, len(originalChildren), len(copyChildren))
|
||||||
|
for i, child := range originalChildren {
|
||||||
|
nextWork = append(nextWork, NodeComparisonWorkItem{child, copyChildren[i]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
work = nextWork
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
362
tools/tsgo/internal/ast/diagnostic.go
Normal file
362
tools/tsgo/internal/ast/diagnostic.go
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/collections"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/diagnostics"
|
||||||
|
"github.com/microsoft/typescript-go/internal/locale"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepopulateDiagnosticKind indicates the kind of repopulation for a diagnostic chain entry.
|
||||||
|
type RepopulateDiagnosticKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RepopulateModeMismatch RepopulateDiagnosticKind = 1
|
||||||
|
RepopulateModuleNotFound RepopulateDiagnosticKind = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepopulateDiagnosticInfo stores information needed to recompute a diagnostic chain entry
|
||||||
|
// during incremental builds when the program state may have changed.
|
||||||
|
type RepopulateDiagnosticInfo struct {
|
||||||
|
Kind RepopulateDiagnosticKind
|
||||||
|
ModuleReference string
|
||||||
|
Mode core.ResolutionMode
|
||||||
|
PackageName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnostic
|
||||||
|
|
||||||
|
type Diagnostic struct {
|
||||||
|
file *SourceFile
|
||||||
|
loc core.TextRange
|
||||||
|
code int32
|
||||||
|
category diagnostics.Category
|
||||||
|
// Original message; may be nil.
|
||||||
|
message *diagnostics.Message
|
||||||
|
messageKey diagnostics.Key
|
||||||
|
messageArgs []string
|
||||||
|
messageChain []*Diagnostic
|
||||||
|
relatedInformation []*Diagnostic
|
||||||
|
reportsUnnecessary bool
|
||||||
|
reportsDeprecated bool
|
||||||
|
skippedOnNoEmit bool
|
||||||
|
repopulateInfo *RepopulateDiagnosticInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Diagnostic) File() *SourceFile { return d.file }
|
||||||
|
func (d *Diagnostic) Pos() int { return d.loc.Pos() }
|
||||||
|
func (d *Diagnostic) End() int { return d.loc.End() }
|
||||||
|
func (d *Diagnostic) Len() int { return d.loc.Len() }
|
||||||
|
func (d *Diagnostic) Loc() core.TextRange { return d.loc }
|
||||||
|
func (d *Diagnostic) Code() int32 { return d.code }
|
||||||
|
func (d *Diagnostic) Category() diagnostics.Category { return d.category }
|
||||||
|
func (d *Diagnostic) MessageKey() diagnostics.Key { return d.messageKey }
|
||||||
|
func (d *Diagnostic) MessageArgs() []string { return d.messageArgs }
|
||||||
|
func (d *Diagnostic) MessageChain() []*Diagnostic { return d.messageChain }
|
||||||
|
func (d *Diagnostic) RelatedInformation() []*Diagnostic { return d.relatedInformation }
|
||||||
|
func (d *Diagnostic) ReportsUnnecessary() bool { return d.reportsUnnecessary }
|
||||||
|
func (d *Diagnostic) ReportsDeprecated() bool { return d.reportsDeprecated }
|
||||||
|
func (d *Diagnostic) SkippedOnNoEmit() bool { return d.skippedOnNoEmit }
|
||||||
|
func (d *Diagnostic) RepopulateInfo() *RepopulateDiagnosticInfo { return d.repopulateInfo }
|
||||||
|
|
||||||
|
func (d *Diagnostic) SetFile(file *SourceFile) { d.file = file }
|
||||||
|
func (d *Diagnostic) SetLocation(loc core.TextRange) { d.loc = loc }
|
||||||
|
func (d *Diagnostic) SetCategory(category diagnostics.Category) { d.category = category }
|
||||||
|
func (d *Diagnostic) SetSkippedOnNoEmit() { d.skippedOnNoEmit = true }
|
||||||
|
func (d *Diagnostic) SetRepopulateInfo(info *RepopulateDiagnosticInfo) { d.repopulateInfo = info }
|
||||||
|
|
||||||
|
func (d *Diagnostic) SetMessageChain(messageChain []*Diagnostic) *Diagnostic {
|
||||||
|
d.messageChain = messageChain
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Diagnostic) AddMessageChain(messageChain *Diagnostic) *Diagnostic {
|
||||||
|
if messageChain != nil {
|
||||||
|
d.messageChain = append(d.messageChain, messageChain)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Diagnostic) SetRelatedInfo(relatedInformation []*Diagnostic) *Diagnostic {
|
||||||
|
d.relatedInformation = relatedInformation
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Diagnostic) AddRelatedInfo(relatedInformation *Diagnostic) *Diagnostic {
|
||||||
|
if relatedInformation != nil {
|
||||||
|
d.relatedInformation = append(d.relatedInformation, relatedInformation)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Diagnostic) Clone() *Diagnostic {
|
||||||
|
result := *d
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Diagnostic) Localize(locale locale.Locale) string {
|
||||||
|
return diagnostics.Localize(locale, d.message, d.messageKey, d.messageArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For debugging only.
|
||||||
|
func (d *Diagnostic) String() string {
|
||||||
|
return diagnostics.Localize(locale.Default, d.message, d.messageKey, d.messageArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDiagnosticFromSerialized(
|
||||||
|
file *SourceFile,
|
||||||
|
loc core.TextRange,
|
||||||
|
code int32,
|
||||||
|
category diagnostics.Category,
|
||||||
|
messageKey diagnostics.Key,
|
||||||
|
messageArgs []string,
|
||||||
|
messageChain []*Diagnostic,
|
||||||
|
relatedInformation []*Diagnostic,
|
||||||
|
reportsUnnecessary bool,
|
||||||
|
reportsDeprecated bool,
|
||||||
|
skippedOnNoEmit bool,
|
||||||
|
) *Diagnostic {
|
||||||
|
return &Diagnostic{
|
||||||
|
file: file,
|
||||||
|
loc: loc,
|
||||||
|
code: code,
|
||||||
|
category: category,
|
||||||
|
messageKey: messageKey,
|
||||||
|
messageArgs: messageArgs,
|
||||||
|
messageChain: messageChain,
|
||||||
|
relatedInformation: relatedInformation,
|
||||||
|
reportsUnnecessary: reportsUnnecessary,
|
||||||
|
reportsDeprecated: reportsDeprecated,
|
||||||
|
skippedOnNoEmit: skippedOnNoEmit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDiagnostic(file *SourceFile, loc core.TextRange, message *diagnostics.Message, args ...any) *Diagnostic {
|
||||||
|
return &Diagnostic{
|
||||||
|
file: file,
|
||||||
|
loc: loc,
|
||||||
|
code: message.Code(),
|
||||||
|
category: message.Category(),
|
||||||
|
message: message,
|
||||||
|
messageKey: message.Key(),
|
||||||
|
messageArgs: diagnostics.StringifyArgs(args),
|
||||||
|
reportsUnnecessary: message.ReportsUnnecessary(),
|
||||||
|
reportsDeprecated: message.ReportsDeprecated(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDiagnosticChain(chain *Diagnostic, message *diagnostics.Message, args ...any) *Diagnostic {
|
||||||
|
if chain != nil {
|
||||||
|
return NewDiagnostic(chain.file, chain.loc, message, args...).AddMessageChain(chain).SetRelatedInfo(chain.relatedInformation)
|
||||||
|
}
|
||||||
|
return NewDiagnostic(nil, core.TextRange{}, message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCompilerDiagnostic(message *diagnostics.Message, args ...any) *Diagnostic {
|
||||||
|
return NewDiagnostic(nil, core.UndefinedTextRange(), message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiagnosticsCollection struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
count int
|
||||||
|
fileDiagnostics map[string][]*Diagnostic
|
||||||
|
fileDiagnosticsSorted collections.Set[string]
|
||||||
|
nonFileDiagnostics []*Diagnostic
|
||||||
|
nonFileDiagnosticsSorted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) Add(diagnostic *Diagnostic) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
c.count++
|
||||||
|
|
||||||
|
if diagnostic.File() != nil {
|
||||||
|
fileName := diagnostic.File().FileName()
|
||||||
|
if c.fileDiagnostics == nil {
|
||||||
|
c.fileDiagnostics = make(map[string][]*Diagnostic)
|
||||||
|
}
|
||||||
|
c.fileDiagnostics[fileName] = append(c.fileDiagnostics[fileName], diagnostic)
|
||||||
|
c.fileDiagnosticsSorted.Delete(fileName)
|
||||||
|
} else {
|
||||||
|
c.nonFileDiagnostics = append(c.nonFileDiagnostics, diagnostic)
|
||||||
|
c.nonFileDiagnosticsSorted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) Lookup(diagnostic *Diagnostic) *Diagnostic {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
var diagnostics []*Diagnostic
|
||||||
|
if diagnostic.File() != nil {
|
||||||
|
diagnostics = c.getDiagnosticsForFileLocked(diagnostic.File().FileName())
|
||||||
|
} else {
|
||||||
|
diagnostics = c.getGlobalDiagnosticsLocked()
|
||||||
|
}
|
||||||
|
if i, ok := slices.BinarySearchFunc(diagnostics, diagnostic, CompareDiagnostics); ok {
|
||||||
|
return diagnostics[i]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) GetGlobalDiagnostics() []*Diagnostic {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
return c.getGlobalDiagnosticsLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) getGlobalDiagnosticsLocked() []*Diagnostic {
|
||||||
|
if !c.nonFileDiagnosticsSorted {
|
||||||
|
slices.SortStableFunc(c.nonFileDiagnostics, CompareDiagnostics)
|
||||||
|
c.nonFileDiagnosticsSorted = true
|
||||||
|
}
|
||||||
|
return slices.Clone(c.nonFileDiagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) GetDiagnosticsForFile(fileName string) []*Diagnostic {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
return c.getDiagnosticsForFileLocked(fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) getDiagnosticsForFileLocked(fileName string) []*Diagnostic {
|
||||||
|
if !c.fileDiagnosticsSorted.Has(fileName) {
|
||||||
|
slices.SortStableFunc(c.fileDiagnostics[fileName], CompareDiagnostics)
|
||||||
|
c.fileDiagnosticsSorted.Add(fileName)
|
||||||
|
}
|
||||||
|
return slices.Clone(c.fileDiagnostics[fileName])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *DiagnosticsCollection) GetDiagnostics() []*Diagnostic {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
diagnostics := make([]*Diagnostic, 0, c.count)
|
||||||
|
diagnostics = append(diagnostics, c.nonFileDiagnostics...)
|
||||||
|
for _, diags := range c.fileDiagnostics {
|
||||||
|
diagnostics = append(diagnostics, diags...)
|
||||||
|
}
|
||||||
|
slices.SortFunc(diagnostics, CompareDiagnostics)
|
||||||
|
return diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDiagnosticPath(d *Diagnostic) string {
|
||||||
|
if d.File() != nil {
|
||||||
|
return d.File().FileName()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func EqualDiagnostics(d1, d2 *Diagnostic) bool {
|
||||||
|
if d1 == d2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return EqualDiagnosticsNoRelatedInfo(d1, d2) &&
|
||||||
|
slices.EqualFunc(d1.RelatedInformation(), d2.RelatedInformation(), EqualDiagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EqualDiagnosticsNoRelatedInfo(d1, d2 *Diagnostic) bool {
|
||||||
|
if d1 == d2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return getDiagnosticPath(d1) == getDiagnosticPath(d2) &&
|
||||||
|
d1.Loc() == d2.Loc() &&
|
||||||
|
d1.Code() == d2.Code() &&
|
||||||
|
slices.Equal(d1.MessageArgs(), d2.MessageArgs()) &&
|
||||||
|
slices.EqualFunc(d1.MessageChain(), d2.MessageChain(), equalMessageChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalMessageChain(c1, c2 *Diagnostic) bool {
|
||||||
|
if c1 == c2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return c1.Code() == c2.Code() &&
|
||||||
|
slices.Equal(c1.MessageArgs(), c2.MessageArgs()) &&
|
||||||
|
slices.EqualFunc(c1.MessageChain(), c2.MessageChain(), equalMessageChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareMessageChainSize(c1, c2 []*Diagnostic) int {
|
||||||
|
c := len(c2) - len(c1)
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
for i := range c1 {
|
||||||
|
c = compareMessageChainSize(c1[i].MessageChain(), c2[i].MessageChain())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareMessageChainContent(c1, c2 []*Diagnostic) int {
|
||||||
|
for i := range c1 {
|
||||||
|
c := slices.Compare(c1[i].MessageArgs(), c2[i].MessageArgs())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c1[i].MessageChain() != nil {
|
||||||
|
c = compareMessageChainContent(c1[i].MessageChain(), c2[i].MessageChain())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareRelatedInfo(r1, r2 []*Diagnostic) int {
|
||||||
|
c := len(r2) - len(r1)
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
for i := range r1 {
|
||||||
|
c = CompareDiagnostics(r1[i], r2[i])
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareDiagnostics(d1, d2 *Diagnostic) int {
|
||||||
|
if d1 == d2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
c := strings.Compare(getDiagnosticPath(d1), getDiagnosticPath(d2))
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c = d1.Loc().Pos() - d2.Loc().Pos()
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c = d1.Loc().End() - d2.Loc().End()
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c = int(d1.Code()) - int(d2.Code())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c = slices.Compare(d1.MessageArgs(), d2.MessageArgs())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c = compareMessageChainSize(d1.MessageChain(), d2.MessageChain())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c = compareMessageChainContent(d1.MessageChain(), d2.MessageChain())
|
||||||
|
if c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return compareRelatedInfo(d1.RelatedInformation(), d2.RelatedInformation())
|
||||||
|
}
|
||||||
75
tools/tsgo/internal/ast/flow.go
Normal file
75
tools/tsgo/internal/ast/flow.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
// FlowFlags
|
||||||
|
|
||||||
|
type FlowFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
FlowFlagsUnreachable FlowFlags = 1 << 0 // Unreachable code
|
||||||
|
FlowFlagsStart FlowFlags = 1 << 1 // Start of flow graph
|
||||||
|
FlowFlagsBranchLabel FlowFlags = 1 << 2 // Non-looping junction
|
||||||
|
FlowFlagsLoopLabel FlowFlags = 1 << 3 // Looping junction
|
||||||
|
FlowFlagsAssignment FlowFlags = 1 << 4 // Assignment
|
||||||
|
FlowFlagsTrueCondition FlowFlags = 1 << 5 // Condition known to be true
|
||||||
|
FlowFlagsFalseCondition FlowFlags = 1 << 6 // Condition known to be false
|
||||||
|
FlowFlagsSwitchClause FlowFlags = 1 << 7 // Switch statement clause
|
||||||
|
FlowFlagsArrayMutation FlowFlags = 1 << 8 // Potential array mutation
|
||||||
|
FlowFlagsCall FlowFlags = 1 << 9 // Potential assertion call
|
||||||
|
FlowFlagsReduceLabel FlowFlags = 1 << 10 // Temporarily reduce antecedents of label
|
||||||
|
FlowFlagsReferenced FlowFlags = 1 << 11 // Referenced as antecedent once
|
||||||
|
FlowFlagsShared FlowFlags = 1 << 12 // Referenced as antecedent more than once
|
||||||
|
FlowFlagsLabel = FlowFlagsBranchLabel | FlowFlagsLoopLabel
|
||||||
|
FlowFlagsCondition = FlowFlagsTrueCondition | FlowFlagsFalseCondition
|
||||||
|
)
|
||||||
|
|
||||||
|
// FlowNode
|
||||||
|
|
||||||
|
type FlowNode struct {
|
||||||
|
Flags FlowFlags
|
||||||
|
Node *Node // Associated AST node
|
||||||
|
Antecedent *FlowNode // Antecedent for all but FlowLabel
|
||||||
|
Antecedents *FlowList // Linked list of antecedents for FlowLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlowList struct {
|
||||||
|
Flow *FlowNode
|
||||||
|
Next *FlowList
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlowLabel = FlowNode
|
||||||
|
|
||||||
|
// FlowSwitchClauseData (synthetic AST node for FlowFlagsSwitchClause)
|
||||||
|
|
||||||
|
type FlowSwitchClauseData struct {
|
||||||
|
NodeBase
|
||||||
|
SwitchStatement *Node
|
||||||
|
ClauseStart int32 // Start index of case/default clause range
|
||||||
|
ClauseEnd int32 // End index of case/default clause range
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFlowSwitchClauseData(switchStatement *Node, clauseStart int, clauseEnd int) *Node {
|
||||||
|
node := &FlowSwitchClauseData{}
|
||||||
|
node.SwitchStatement = switchStatement
|
||||||
|
node.ClauseStart = int32(clauseStart)
|
||||||
|
node.ClauseEnd = int32(clauseEnd)
|
||||||
|
return newNode(KindUnknown, node, NodeFactoryHooks{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *FlowSwitchClauseData) IsEmpty() bool {
|
||||||
|
return node.ClauseStart == node.ClauseEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlowReduceLabelData (synthetic AST node for FlowFlagsReduceLabel)
|
||||||
|
|
||||||
|
type FlowReduceLabelData struct {
|
||||||
|
NodeBase
|
||||||
|
Target *FlowLabel // Target label
|
||||||
|
Antecedents *FlowList // Temporary antecedent list
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFlowReduceLabelData(target *FlowLabel, antecedents *FlowList) *Node {
|
||||||
|
node := &FlowReduceLabelData{}
|
||||||
|
node.Target = target
|
||||||
|
node.Antecedents = antecedents
|
||||||
|
return newNode(KindUnknown, node, NodeFactoryHooks{})
|
||||||
|
}
|
||||||
37
tools/tsgo/internal/ast/functionflags.go
Normal file
37
tools/tsgo/internal/ast/functionflags.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type FunctionFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
FunctionFlagsNormal FunctionFlags = 0
|
||||||
|
FunctionFlagsGenerator FunctionFlags = 1 << 0
|
||||||
|
FunctionFlagsAsync FunctionFlags = 1 << 1
|
||||||
|
FunctionFlagsInvalid FunctionFlags = 1 << 2
|
||||||
|
FunctionFlagsAsyncGenerator FunctionFlags = FunctionFlagsAsync | FunctionFlagsGenerator
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetFunctionFlags(node *Node) FunctionFlags {
|
||||||
|
if node == nil {
|
||||||
|
return FunctionFlagsInvalid
|
||||||
|
}
|
||||||
|
data := node.BodyData()
|
||||||
|
if data == nil {
|
||||||
|
return FunctionFlagsInvalid
|
||||||
|
}
|
||||||
|
flags := FunctionFlagsNormal
|
||||||
|
switch node.Kind {
|
||||||
|
case KindFunctionDeclaration, KindFunctionExpression, KindMethodDeclaration:
|
||||||
|
if data.AsteriskToken != nil {
|
||||||
|
flags |= FunctionFlagsGenerator
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case KindArrowFunction:
|
||||||
|
if HasSyntacticModifier(node, ModifierFlagsAsync) {
|
||||||
|
flags |= FunctionFlagsAsync
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data.Body == nil {
|
||||||
|
flags |= FunctionFlagsInvalid
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
6
tools/tsgo/internal/ast/ids.go
Normal file
6
tools/tsgo/internal/ast/ids.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type (
|
||||||
|
NodeId uint64
|
||||||
|
SymbolId uint64
|
||||||
|
)
|
||||||
463
tools/tsgo/internal/ast/kind_generated.go
Normal file
463
tools/tsgo/internal/ast/kind_generated.go
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
// Code generated by _scripts/generate-go-ast.ts. DO NOT EDIT.
|
||||||
|
|
||||||
|
package ast
|
||||||
|
|
||||||
|
//go:generate go tool golang.org/x/tools/cmd/stringer -type=Kind -output=kind_stringer_generated.go
|
||||||
|
//go:generate npx dprint fmt kind_stringer_generated.go
|
||||||
|
|
||||||
|
type Kind int16
|
||||||
|
|
||||||
|
const (
|
||||||
|
KindUnknown Kind = iota
|
||||||
|
KindEndOfFile
|
||||||
|
KindSingleLineCommentTrivia
|
||||||
|
KindMultiLineCommentTrivia
|
||||||
|
KindNewLineTrivia
|
||||||
|
KindWhitespaceTrivia
|
||||||
|
KindConflictMarkerTrivia
|
||||||
|
KindNonTextFileMarkerTrivia
|
||||||
|
KindNumericLiteral
|
||||||
|
KindBigIntLiteral
|
||||||
|
KindStringLiteral
|
||||||
|
KindJsxText
|
||||||
|
KindJsxTextAllWhiteSpaces
|
||||||
|
KindRegularExpressionLiteral
|
||||||
|
KindNoSubstitutionTemplateLiteral
|
||||||
|
// Pseudo-literals
|
||||||
|
KindTemplateHead
|
||||||
|
KindTemplateMiddle
|
||||||
|
KindTemplateTail
|
||||||
|
// Punctuation
|
||||||
|
KindOpenBraceToken
|
||||||
|
KindCloseBraceToken
|
||||||
|
KindOpenParenToken
|
||||||
|
KindCloseParenToken
|
||||||
|
KindOpenBracketToken
|
||||||
|
KindCloseBracketToken
|
||||||
|
KindDotToken
|
||||||
|
KindDotDotDotToken
|
||||||
|
KindSemicolonToken
|
||||||
|
KindCommaToken
|
||||||
|
KindQuestionDotToken
|
||||||
|
KindLessThanToken
|
||||||
|
KindLessThanSlashToken
|
||||||
|
KindGreaterThanToken
|
||||||
|
KindLessThanEqualsToken
|
||||||
|
KindGreaterThanEqualsToken
|
||||||
|
KindEqualsEqualsToken
|
||||||
|
KindExclamationEqualsToken
|
||||||
|
KindEqualsEqualsEqualsToken
|
||||||
|
KindExclamationEqualsEqualsToken
|
||||||
|
KindEqualsGreaterThanToken
|
||||||
|
KindPlusToken
|
||||||
|
KindMinusToken
|
||||||
|
KindAsteriskToken
|
||||||
|
KindAsteriskAsteriskToken
|
||||||
|
KindSlashToken
|
||||||
|
KindPercentToken
|
||||||
|
KindPlusPlusToken
|
||||||
|
KindMinusMinusToken
|
||||||
|
KindLessThanLessThanToken
|
||||||
|
KindGreaterThanGreaterThanToken
|
||||||
|
KindGreaterThanGreaterThanGreaterThanToken
|
||||||
|
KindAmpersandToken
|
||||||
|
KindBarToken
|
||||||
|
KindCaretToken
|
||||||
|
KindExclamationToken
|
||||||
|
KindTildeToken
|
||||||
|
KindAmpersandAmpersandToken
|
||||||
|
KindBarBarToken
|
||||||
|
KindQuestionToken
|
||||||
|
KindColonToken
|
||||||
|
KindAtToken
|
||||||
|
KindQuestionQuestionToken
|
||||||
|
// Only the JSDoc scanner produces BacktickToken. The normal scanner produces NoSubstitutionTemplateLiteral and related kinds.
|
||||||
|
KindBacktickToken
|
||||||
|
// Only the JSDoc scanner produces HashToken. The normal scanner produces PrivateIdentifier.
|
||||||
|
KindHashToken
|
||||||
|
// Assignments
|
||||||
|
KindEqualsToken
|
||||||
|
KindPlusEqualsToken
|
||||||
|
KindMinusEqualsToken
|
||||||
|
KindAsteriskEqualsToken
|
||||||
|
KindAsteriskAsteriskEqualsToken
|
||||||
|
KindSlashEqualsToken
|
||||||
|
KindPercentEqualsToken
|
||||||
|
KindLessThanLessThanEqualsToken
|
||||||
|
KindGreaterThanGreaterThanEqualsToken
|
||||||
|
KindGreaterThanGreaterThanGreaterThanEqualsToken
|
||||||
|
KindAmpersandEqualsToken
|
||||||
|
KindBarEqualsToken
|
||||||
|
KindBarBarEqualsToken
|
||||||
|
KindAmpersandAmpersandEqualsToken
|
||||||
|
KindQuestionQuestionEqualsToken
|
||||||
|
KindCaretEqualsToken
|
||||||
|
// Identifiers and PrivateIdentifier
|
||||||
|
KindIdentifier
|
||||||
|
KindPrivateIdentifier
|
||||||
|
KindJSDocCommentTextToken
|
||||||
|
// Reserved words
|
||||||
|
KindBreakKeyword
|
||||||
|
KindCaseKeyword
|
||||||
|
KindCatchKeyword
|
||||||
|
KindClassKeyword
|
||||||
|
KindConstKeyword
|
||||||
|
KindContinueKeyword
|
||||||
|
KindDebuggerKeyword
|
||||||
|
KindDefaultKeyword
|
||||||
|
KindDeleteKeyword
|
||||||
|
KindDoKeyword
|
||||||
|
KindElseKeyword
|
||||||
|
KindEnumKeyword
|
||||||
|
KindExportKeyword
|
||||||
|
KindExtendsKeyword
|
||||||
|
KindFalseKeyword
|
||||||
|
KindFinallyKeyword
|
||||||
|
KindForKeyword
|
||||||
|
KindFunctionKeyword
|
||||||
|
KindIfKeyword
|
||||||
|
KindImportKeyword
|
||||||
|
KindInKeyword
|
||||||
|
KindInstanceOfKeyword
|
||||||
|
KindNewKeyword
|
||||||
|
KindNullKeyword
|
||||||
|
KindReturnKeyword
|
||||||
|
KindSuperKeyword
|
||||||
|
KindSwitchKeyword
|
||||||
|
KindThisKeyword
|
||||||
|
KindThrowKeyword
|
||||||
|
KindTrueKeyword
|
||||||
|
KindTryKeyword
|
||||||
|
KindTypeOfKeyword
|
||||||
|
KindVarKeyword
|
||||||
|
KindVoidKeyword
|
||||||
|
KindWhileKeyword
|
||||||
|
KindWithKeyword
|
||||||
|
// Strict mode reserved words
|
||||||
|
KindImplementsKeyword
|
||||||
|
KindInterfaceKeyword
|
||||||
|
KindLetKeyword
|
||||||
|
KindPackageKeyword
|
||||||
|
KindPrivateKeyword
|
||||||
|
KindProtectedKeyword
|
||||||
|
KindPublicKeyword
|
||||||
|
KindStaticKeyword
|
||||||
|
KindYieldKeyword
|
||||||
|
// Contextual keywords
|
||||||
|
KindAbstractKeyword
|
||||||
|
KindAccessorKeyword
|
||||||
|
KindAsKeyword
|
||||||
|
KindAssertsKeyword
|
||||||
|
KindAssertKeyword
|
||||||
|
KindAnyKeyword
|
||||||
|
KindAsyncKeyword
|
||||||
|
KindAwaitKeyword
|
||||||
|
KindBooleanKeyword
|
||||||
|
KindConstructorKeyword
|
||||||
|
KindDeclareKeyword
|
||||||
|
KindGetKeyword
|
||||||
|
KindImmediateKeyword
|
||||||
|
KindInferKeyword
|
||||||
|
KindIntrinsicKeyword
|
||||||
|
KindIsKeyword
|
||||||
|
KindKeyOfKeyword
|
||||||
|
KindModuleKeyword
|
||||||
|
KindNamespaceKeyword
|
||||||
|
KindNeverKeyword
|
||||||
|
KindOutKeyword
|
||||||
|
KindReadonlyKeyword
|
||||||
|
KindRequireKeyword
|
||||||
|
KindNumberKeyword
|
||||||
|
KindObjectKeyword
|
||||||
|
KindSatisfiesKeyword
|
||||||
|
KindSetKeyword
|
||||||
|
KindStringKeyword
|
||||||
|
KindSymbolKeyword
|
||||||
|
KindTypeKeyword
|
||||||
|
KindUndefinedKeyword
|
||||||
|
KindUniqueKeyword
|
||||||
|
KindUnknownKeyword
|
||||||
|
KindUsingKeyword
|
||||||
|
KindFromKeyword
|
||||||
|
KindGlobalKeyword
|
||||||
|
KindBigIntKeyword
|
||||||
|
KindOverrideKeyword
|
||||||
|
KindOfKeyword
|
||||||
|
KindDeferKeyword // LastKeyword and LastToken and LastContextualKeyword
|
||||||
|
// Parse tree nodes
|
||||||
|
// Names
|
||||||
|
KindQualifiedName
|
||||||
|
KindComputedPropertyName
|
||||||
|
// Signature elements
|
||||||
|
KindTypeParameter
|
||||||
|
KindParameter
|
||||||
|
KindDecorator
|
||||||
|
// TypeMember
|
||||||
|
KindPropertySignature
|
||||||
|
KindPropertyDeclaration
|
||||||
|
KindMethodSignature
|
||||||
|
KindMethodDeclaration
|
||||||
|
KindClassStaticBlockDeclaration
|
||||||
|
KindConstructor
|
||||||
|
KindGetAccessor
|
||||||
|
KindSetAccessor
|
||||||
|
KindCallSignature
|
||||||
|
KindConstructSignature
|
||||||
|
KindIndexSignature
|
||||||
|
// Type
|
||||||
|
KindTypePredicate
|
||||||
|
KindTypeReference
|
||||||
|
KindFunctionType
|
||||||
|
KindConstructorType
|
||||||
|
KindTypeQuery
|
||||||
|
KindTypeLiteral
|
||||||
|
KindArrayType
|
||||||
|
KindTupleType
|
||||||
|
KindOptionalType
|
||||||
|
KindRestType
|
||||||
|
KindUnionType
|
||||||
|
KindIntersectionType
|
||||||
|
KindConditionalType
|
||||||
|
KindInferType
|
||||||
|
KindParenthesizedType
|
||||||
|
KindThisType
|
||||||
|
KindTypeOperator
|
||||||
|
KindIndexedAccessType
|
||||||
|
KindMappedType
|
||||||
|
KindLiteralType
|
||||||
|
KindNamedTupleMember
|
||||||
|
KindTemplateLiteralType
|
||||||
|
KindTemplateLiteralTypeSpan
|
||||||
|
KindImportType
|
||||||
|
// Binding patterns
|
||||||
|
KindObjectBindingPattern
|
||||||
|
KindArrayBindingPattern
|
||||||
|
KindBindingElement
|
||||||
|
// Expression
|
||||||
|
KindArrayLiteralExpression
|
||||||
|
KindObjectLiteralExpression
|
||||||
|
KindPropertyAccessExpression
|
||||||
|
KindElementAccessExpression
|
||||||
|
KindCallExpression
|
||||||
|
KindNewExpression
|
||||||
|
KindTaggedTemplateExpression
|
||||||
|
KindTypeAssertionExpression
|
||||||
|
KindParenthesizedExpression
|
||||||
|
KindFunctionExpression
|
||||||
|
KindArrowFunction
|
||||||
|
KindDeleteExpression
|
||||||
|
KindTypeOfExpression
|
||||||
|
KindVoidExpression
|
||||||
|
KindAwaitExpression
|
||||||
|
KindPrefixUnaryExpression
|
||||||
|
KindPostfixUnaryExpression
|
||||||
|
KindBinaryExpression
|
||||||
|
KindConditionalExpression
|
||||||
|
KindTemplateExpression
|
||||||
|
KindYieldExpression
|
||||||
|
KindSpreadElement
|
||||||
|
KindClassExpression
|
||||||
|
KindOmittedExpression
|
||||||
|
KindExpressionWithTypeArguments
|
||||||
|
KindAsExpression
|
||||||
|
KindNonNullExpression
|
||||||
|
KindMetaProperty
|
||||||
|
KindSyntheticExpression
|
||||||
|
KindSatisfiesExpression
|
||||||
|
// Misc
|
||||||
|
KindTemplateSpan
|
||||||
|
KindSemicolonClassElement
|
||||||
|
// Element
|
||||||
|
KindBlock
|
||||||
|
KindEmptyStatement
|
||||||
|
KindVariableStatement
|
||||||
|
KindExpressionStatement
|
||||||
|
KindIfStatement
|
||||||
|
KindDoStatement
|
||||||
|
KindWhileStatement
|
||||||
|
KindForStatement
|
||||||
|
KindForInStatement
|
||||||
|
KindForOfStatement
|
||||||
|
KindContinueStatement
|
||||||
|
KindBreakStatement
|
||||||
|
KindReturnStatement
|
||||||
|
KindWithStatement
|
||||||
|
KindSwitchStatement
|
||||||
|
KindLabeledStatement
|
||||||
|
KindThrowStatement
|
||||||
|
KindTryStatement
|
||||||
|
KindDebuggerStatement
|
||||||
|
KindVariableDeclaration
|
||||||
|
KindVariableDeclarationList
|
||||||
|
KindFunctionDeclaration
|
||||||
|
KindClassDeclaration
|
||||||
|
KindInterfaceDeclaration
|
||||||
|
KindTypeAliasDeclaration
|
||||||
|
KindEnumDeclaration
|
||||||
|
KindModuleDeclaration
|
||||||
|
KindModuleBlock
|
||||||
|
KindCaseBlock
|
||||||
|
KindNamespaceExportDeclaration
|
||||||
|
KindImportEqualsDeclaration
|
||||||
|
KindImportDeclaration
|
||||||
|
KindImportClause
|
||||||
|
KindNamespaceImport
|
||||||
|
KindNamedImports
|
||||||
|
KindImportSpecifier
|
||||||
|
KindExportAssignment
|
||||||
|
KindExportDeclaration
|
||||||
|
KindNamedExports
|
||||||
|
KindNamespaceExport
|
||||||
|
KindExportSpecifier
|
||||||
|
KindMissingDeclaration
|
||||||
|
// Module references
|
||||||
|
KindExternalModuleReference
|
||||||
|
// JSX
|
||||||
|
KindJsxElement
|
||||||
|
KindJsxSelfClosingElement
|
||||||
|
KindJsxOpeningElement
|
||||||
|
KindJsxClosingElement
|
||||||
|
KindJsxFragment
|
||||||
|
KindJsxOpeningFragment
|
||||||
|
KindJsxClosingFragment
|
||||||
|
KindJsxAttribute
|
||||||
|
KindJsxAttributes
|
||||||
|
KindJsxSpreadAttribute
|
||||||
|
KindJsxExpression
|
||||||
|
KindJsxNamespacedName
|
||||||
|
// Clauses
|
||||||
|
KindCaseClause
|
||||||
|
KindDefaultClause
|
||||||
|
KindHeritageClause
|
||||||
|
KindCatchClause
|
||||||
|
// Import attributes
|
||||||
|
KindImportAttributes
|
||||||
|
KindImportAttribute
|
||||||
|
// Property assignments
|
||||||
|
KindPropertyAssignment
|
||||||
|
KindShorthandPropertyAssignment
|
||||||
|
KindSpreadAssignment
|
||||||
|
// Enum
|
||||||
|
KindEnumMember
|
||||||
|
// Top-level nodes
|
||||||
|
KindSourceFile
|
||||||
|
// JSDoc nodes
|
||||||
|
KindJSDocTypeExpression
|
||||||
|
KindJSDocNameReference
|
||||||
|
KindJSDocAllType // The * type
|
||||||
|
KindJSDocNullableType
|
||||||
|
KindJSDocNonNullableType
|
||||||
|
KindJSDocOptionalType
|
||||||
|
KindJSDocVariadicType
|
||||||
|
KindJSDoc
|
||||||
|
KindJSDocText
|
||||||
|
KindJSDocTypeLiteral
|
||||||
|
KindJSDocSignature
|
||||||
|
KindJSDocLink
|
||||||
|
KindJSDocLinkCode
|
||||||
|
KindJSDocLinkPlain
|
||||||
|
KindJSDocUnknownTag
|
||||||
|
KindJSDocAugmentsTag
|
||||||
|
KindJSDocImplementsTag
|
||||||
|
KindJSDocDeprecatedTag
|
||||||
|
KindJSDocPublicTag
|
||||||
|
KindJSDocPrivateTag
|
||||||
|
KindJSDocProtectedTag
|
||||||
|
KindJSDocReadonlyTag
|
||||||
|
KindJSDocOverrideTag
|
||||||
|
KindJSDocCallbackTag
|
||||||
|
KindJSDocOverloadTag
|
||||||
|
KindJSDocParameterTag
|
||||||
|
KindJSDocReturnTag
|
||||||
|
KindJSDocThisTag
|
||||||
|
KindJSDocTypeTag
|
||||||
|
KindJSDocTemplateTag
|
||||||
|
KindJSDocTypedefTag
|
||||||
|
KindJSDocSeeTag
|
||||||
|
KindJSDocPropertyTag
|
||||||
|
KindJSDocThrowsTag
|
||||||
|
KindJSDocSatisfiesTag
|
||||||
|
KindJSDocImportTag
|
||||||
|
// Synthesized list
|
||||||
|
KindSyntaxList
|
||||||
|
// Reparsed JS nodes
|
||||||
|
KindJSTypeAliasDeclaration
|
||||||
|
KindJSImportDeclaration
|
||||||
|
// Transformation nodes
|
||||||
|
KindNotEmittedStatement
|
||||||
|
KindPartiallyEmittedExpression
|
||||||
|
KindSyntheticReferenceExpression
|
||||||
|
KindNotEmittedTypeElement
|
||||||
|
KindCount
|
||||||
|
KindFirstAssignment = KindEqualsToken
|
||||||
|
KindLastAssignment = KindCaretEqualsToken
|
||||||
|
KindFirstCompoundAssignment = KindPlusEqualsToken
|
||||||
|
KindLastCompoundAssignment = KindCaretEqualsToken
|
||||||
|
KindFirstReservedWord = KindBreakKeyword
|
||||||
|
KindLastReservedWord = KindWithKeyword
|
||||||
|
KindFirstKeyword = KindBreakKeyword
|
||||||
|
KindLastKeyword = KindDeferKeyword
|
||||||
|
KindFirstFutureReservedWord = KindImplementsKeyword
|
||||||
|
KindLastFutureReservedWord = KindYieldKeyword
|
||||||
|
KindFirstTypeNode = KindTypePredicate
|
||||||
|
KindLastTypeNode = KindImportType
|
||||||
|
KindFirstPunctuation = KindOpenBraceToken
|
||||||
|
KindLastPunctuation = KindCaretEqualsToken
|
||||||
|
KindFirstToken = KindUnknown
|
||||||
|
KindLastToken = KindLastKeyword
|
||||||
|
KindFirstLiteralToken = KindNumericLiteral
|
||||||
|
KindLastLiteralToken = KindNoSubstitutionTemplateLiteral
|
||||||
|
KindFirstTemplateToken = KindNoSubstitutionTemplateLiteral
|
||||||
|
KindLastTemplateToken = KindTemplateTail
|
||||||
|
KindFirstBinaryOperator = KindLessThanToken
|
||||||
|
KindLastBinaryOperator = KindCaretEqualsToken
|
||||||
|
KindFirstStatement = KindVariableStatement
|
||||||
|
KindLastStatement = KindDebuggerStatement
|
||||||
|
KindFirstNode = KindQualifiedName
|
||||||
|
KindFirstJSDocNode = KindJSDocTypeExpression
|
||||||
|
KindLastJSDocNode = KindJSDocImportTag
|
||||||
|
KindFirstJSDocTagNode = KindJSDocUnknownTag
|
||||||
|
KindLastJSDocTagNode = KindJSDocImportTag
|
||||||
|
KindFirstContextualKeyword = KindAbstractKeyword
|
||||||
|
KindLastContextualKeyword = KindDeferKeyword
|
||||||
|
KindLastUnaryOperator = KindTildeToken
|
||||||
|
KindFirstTriviaToken = KindSingleLineCommentTrivia
|
||||||
|
KindLastTriviaToken = KindConflictMarkerTrivia
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
TriviaSyntaxKind = Kind // KindSingleLineCommentTrivia | KindMultiLineCommentTrivia | KindNewLineTrivia | KindWhitespaceTrivia | KindConflictMarkerTrivia
|
||||||
|
LiteralSyntaxKind = Kind // KindNumericLiteral | KindBigIntLiteral | KindStringLiteral | KindJsxText | KindJsxTextAllWhiteSpaces | KindRegularExpressionLiteral | KindNoSubstitutionTemplateLiteral
|
||||||
|
PseudoLiteralSyntaxKind = Kind // KindTemplateHead | KindTemplateMiddle | KindTemplateTail
|
||||||
|
PunctuationSyntaxKind = Kind // KindOpenBraceToken | KindCloseBraceToken | KindOpenParenToken | KindCloseParenToken | KindOpenBracketToken | KindCloseBracketToken | KindDotToken | KindDotDotDotToken | KindSemicolonToken | KindCommaToken | KindQuestionDotToken | KindLessThanToken | KindLessThanSlashToken | KindGreaterThanToken | KindLessThanEqualsToken | KindGreaterThanEqualsToken | KindEqualsEqualsToken | KindExclamationEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindEqualsGreaterThanToken | KindPlusToken | KindMinusToken | KindAsteriskToken | KindAsteriskAsteriskToken | KindSlashToken | KindPercentToken | KindPlusPlusToken | KindMinusMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindExclamationToken | KindTildeToken | KindAmpersandAmpersandToken | KindBarBarToken | KindQuestionToken | KindColonToken | KindAtToken | KindQuestionQuestionToken | KindBacktickToken | KindHashToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskEqualsToken | KindAsteriskAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken | KindCaretEqualsToken
|
||||||
|
KeywordSyntaxKind = Kind // KindBreakKeyword | KindCaseKeyword | KindCatchKeyword | KindClassKeyword | KindConstKeyword | KindContinueKeyword | KindDebuggerKeyword | KindDefaultKeyword | KindDeleteKeyword | KindDoKeyword | KindElseKeyword | KindEnumKeyword | KindExportKeyword | KindExtendsKeyword | KindFalseKeyword | KindFinallyKeyword | KindForKeyword | KindFunctionKeyword | KindIfKeyword | KindImportKeyword | KindInKeyword | KindInstanceOfKeyword | KindNewKeyword | KindNullKeyword | KindReturnKeyword | KindSuperKeyword | KindSwitchKeyword | KindThisKeyword | KindThrowKeyword | KindTrueKeyword | KindTryKeyword | KindTypeOfKeyword | KindVarKeyword | KindVoidKeyword | KindWhileKeyword | KindWithKeyword | KindImplementsKeyword | KindInterfaceKeyword | KindLetKeyword | KindPackageKeyword | KindPrivateKeyword | KindProtectedKeyword | KindPublicKeyword | KindStaticKeyword | KindYieldKeyword | KindAbstractKeyword | KindAccessorKeyword | KindAsKeyword | KindAssertsKeyword | KindAssertKeyword | KindAnyKeyword | KindAsyncKeyword | KindAwaitKeyword | KindBooleanKeyword | KindConstructorKeyword | KindDeclareKeyword | KindGetKeyword | KindImmediateKeyword | KindInferKeyword | KindIntrinsicKeyword | KindIsKeyword | KindKeyOfKeyword | KindModuleKeyword | KindNamespaceKeyword | KindNeverKeyword | KindOutKeyword | KindReadonlyKeyword | KindRequireKeyword | KindNumberKeyword | KindObjectKeyword | KindSatisfiesKeyword | KindSetKeyword | KindStringKeyword | KindSymbolKeyword | KindTypeKeyword | KindUndefinedKeyword | KindUniqueKeyword | KindUnknownKeyword | KindUsingKeyword | KindFromKeyword | KindGlobalKeyword | KindBigIntKeyword | KindOverrideKeyword | KindOfKeyword | KindDeferKeyword
|
||||||
|
ModifierSyntaxKind = Kind // KindAbstractKeyword | KindAccessorKeyword | KindAsyncKeyword | KindConstKeyword | KindDeclareKeyword | KindDefaultKeyword | KindExportKeyword | KindInKeyword | KindPrivateKeyword | KindProtectedKeyword | KindPublicKeyword | KindReadonlyKeyword | KindOutKeyword | KindOverrideKeyword | KindStaticKeyword
|
||||||
|
KeywordTypeSyntaxKind = Kind // KindAnyKeyword | KindBigIntKeyword | KindBooleanKeyword | KindIntrinsicKeyword | KindNeverKeyword | KindNumberKeyword | KindObjectKeyword | KindStringKeyword | KindSymbolKeyword | KindUndefinedKeyword | KindUnknownKeyword | KindVoidKeyword
|
||||||
|
KeywordExpressionSyntaxKind = Kind // KindNullKeyword | KindTrueKeyword | KindFalseKeyword | KindThisKeyword | KindSuperKeyword | KindImportKeyword
|
||||||
|
TokenSyntaxKind = Kind // KindUnknown | KindEndOfFile | KindSingleLineCommentTrivia | KindMultiLineCommentTrivia | KindNewLineTrivia | KindWhitespaceTrivia | KindConflictMarkerTrivia | KindNonTextFileMarkerTrivia | KindNumericLiteral | KindBigIntLiteral | KindStringLiteral | KindJsxText | KindJsxTextAllWhiteSpaces | KindRegularExpressionLiteral | KindNoSubstitutionTemplateLiteral | KindTemplateHead | KindTemplateMiddle | KindTemplateTail | KindOpenBraceToken | KindCloseBraceToken | KindOpenParenToken | KindCloseParenToken | KindOpenBracketToken | KindCloseBracketToken | KindDotToken | KindDotDotDotToken | KindSemicolonToken | KindCommaToken | KindQuestionDotToken | KindLessThanToken | KindLessThanSlashToken | KindGreaterThanToken | KindLessThanEqualsToken | KindGreaterThanEqualsToken | KindEqualsEqualsToken | KindExclamationEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindEqualsGreaterThanToken | KindPlusToken | KindMinusToken | KindAsteriskToken | KindAsteriskAsteriskToken | KindSlashToken | KindPercentToken | KindPlusPlusToken | KindMinusMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindExclamationToken | KindTildeToken | KindAmpersandAmpersandToken | KindBarBarToken | KindQuestionToken | KindColonToken | KindAtToken | KindQuestionQuestionToken | KindBacktickToken | KindHashToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskEqualsToken | KindAsteriskAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken | KindCaretEqualsToken | KindIdentifier | KindPrivateIdentifier | KindJSDocCommentTextToken | KindBreakKeyword | KindCaseKeyword | KindCatchKeyword | KindClassKeyword | KindConstKeyword | KindContinueKeyword | KindDebuggerKeyword | KindDefaultKeyword | KindDeleteKeyword | KindDoKeyword | KindElseKeyword | KindEnumKeyword | KindExportKeyword | KindExtendsKeyword | KindFalseKeyword | KindFinallyKeyword | KindForKeyword | KindFunctionKeyword | KindIfKeyword | KindImportKeyword | KindInKeyword | KindInstanceOfKeyword | KindNewKeyword | KindNullKeyword | KindReturnKeyword | KindSuperKeyword | KindSwitchKeyword | KindThisKeyword | KindThrowKeyword | KindTrueKeyword | KindTryKeyword | KindTypeOfKeyword | KindVarKeyword | KindVoidKeyword | KindWhileKeyword | KindWithKeyword | KindImplementsKeyword | KindInterfaceKeyword | KindLetKeyword | KindPackageKeyword | KindPrivateKeyword | KindProtectedKeyword | KindPublicKeyword | KindStaticKeyword | KindYieldKeyword | KindAbstractKeyword | KindAccessorKeyword | KindAsKeyword | KindAssertsKeyword | KindAssertKeyword | KindAnyKeyword | KindAsyncKeyword | KindAwaitKeyword | KindBooleanKeyword | KindConstructorKeyword | KindDeclareKeyword | KindGetKeyword | KindImmediateKeyword | KindInferKeyword | KindIntrinsicKeyword | KindIsKeyword | KindKeyOfKeyword | KindModuleKeyword | KindNamespaceKeyword | KindNeverKeyword | KindOutKeyword | KindReadonlyKeyword | KindRequireKeyword | KindNumberKeyword | KindObjectKeyword | KindSatisfiesKeyword | KindSetKeyword | KindStringKeyword | KindSymbolKeyword | KindTypeKeyword | KindUndefinedKeyword | KindUniqueKeyword | KindUnknownKeyword | KindUsingKeyword | KindFromKeyword | KindGlobalKeyword | KindBigIntKeyword | KindOverrideKeyword | KindOfKeyword | KindDeferKeyword
|
||||||
|
JsxTokenSyntaxKind = Kind // KindLessThanSlashToken | KindEndOfFile | KindConflictMarkerTrivia | KindJsxText | KindJsxTextAllWhiteSpaces | KindOpenBraceToken | KindLessThanToken
|
||||||
|
JSDocNodeSyntaxKind = Kind // KindJSDocTypeExpression | KindJSDocNameReference | KindJSDocAllType | KindJSDocNullableType | KindJSDocNonNullableType | KindJSDocOptionalType | KindJSDocVariadicType | KindJSDoc | KindJSDocText | KindJSDocTypeLiteral | KindJSDocSignature | KindJSDocLink | KindJSDocLinkCode | KindJSDocLinkPlain | KindJSDocUnknownTag | KindJSDocAugmentsTag | KindJSDocImplementsTag | KindJSDocDeprecatedTag | KindJSDocPublicTag | KindJSDocPrivateTag | KindJSDocProtectedTag | KindJSDocReadonlyTag | KindJSDocOverrideTag | KindJSDocCallbackTag | KindJSDocOverloadTag | KindJSDocParameterTag | KindJSDocReturnTag | KindJSDocThisTag | KindJSDocTypeTag | KindJSDocTemplateTag | KindJSDocTypedefTag | KindJSDocSeeTag | KindJSDocPropertyTag | KindJSDocThrowsTag | KindJSDocSatisfiesTag | KindJSDocImportTag
|
||||||
|
ImportPhaseModifierSyntaxKind = Kind // KindTypeKeyword | KindDeferKeyword
|
||||||
|
PostfixUnaryOperator = Kind // KindPlusPlusToken | KindMinusMinusToken
|
||||||
|
PrefixUnaryOperator = Kind // KindPlusToken | KindMinusToken | KindTildeToken | KindExclamationToken | KindPlusPlusToken | KindMinusMinusToken
|
||||||
|
AssignmentOperator = Kind // KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken
|
||||||
|
BinaryOperator = Kind // KindQuestionQuestionToken | KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindAmpersandAmpersandToken | KindBarBarToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken | KindCommaToken
|
||||||
|
ExponentiationOperator = Kind // KindAsteriskAsteriskToken
|
||||||
|
MultiplicativeOperator = Kind // KindAsteriskToken | KindSlashToken | KindPercentToken
|
||||||
|
MultiplicativeOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken
|
||||||
|
AdditiveOperator = Kind // KindPlusToken | KindMinusToken
|
||||||
|
AdditiveOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken
|
||||||
|
ShiftOperator = Kind // KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken
|
||||||
|
ShiftOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken
|
||||||
|
RelationalOperator = Kind // KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword
|
||||||
|
RelationalOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword
|
||||||
|
EqualityOperator = Kind // KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken
|
||||||
|
EqualityOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken
|
||||||
|
BitwiseOperator = Kind // KindAmpersandToken | KindBarToken | KindCaretToken
|
||||||
|
BitwiseOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken
|
||||||
|
LogicalOperator = Kind // KindAmpersandAmpersandToken | KindBarBarToken
|
||||||
|
LogicalOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindAmpersandAmpersandToken | KindBarBarToken
|
||||||
|
CompoundAssignmentOperator = Kind // KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken
|
||||||
|
AssignmentOperatorOrHigher = Kind // KindQuestionQuestionToken | KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindAmpersandAmpersandToken | KindBarBarToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken
|
||||||
|
LogicalOrCoalescingAssignmentOperator = Kind // KindAmpersandAmpersandEqualsToken | KindBarBarEqualsToken | KindQuestionQuestionEqualsToken
|
||||||
|
)
|
||||||
375
tools/tsgo/internal/ast/kind_stringer_generated.go
Normal file
375
tools/tsgo/internal/ast/kind_stringer_generated.go
Normal file
File diff suppressed because one or more lines are too long
53
tools/tsgo/internal/ast/modifierflags.go
Normal file
53
tools/tsgo/internal/ast/modifierflags.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type ModifierFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModifierFlagsNone ModifierFlags = 0
|
||||||
|
// Syntactic/JSDoc modifiers
|
||||||
|
ModifierFlagsPublic ModifierFlags = 1 << 0 // Property/Method
|
||||||
|
ModifierFlagsPrivate ModifierFlags = 1 << 1 // Property/Method
|
||||||
|
ModifierFlagsProtected ModifierFlags = 1 << 2 // Property/Method
|
||||||
|
ModifierFlagsReadonly ModifierFlags = 1 << 3 // Property/Method
|
||||||
|
ModifierFlagsOverride ModifierFlags = 1 << 4 // Override method
|
||||||
|
// Syntactic-only modifiers
|
||||||
|
ModifierFlagsExport ModifierFlags = 1 << 5 // Declarations
|
||||||
|
ModifierFlagsAbstract ModifierFlags = 1 << 6 // Class/Method/ConstructSignature
|
||||||
|
ModifierFlagsAmbient ModifierFlags = 1 << 7 // Declarations (declare keyword)
|
||||||
|
ModifierFlagsStatic ModifierFlags = 1 << 8 // Property/Method
|
||||||
|
ModifierFlagsAccessor ModifierFlags = 1 << 9 // Property
|
||||||
|
ModifierFlagsAsync ModifierFlags = 1 << 10 // Property/Method/Function
|
||||||
|
ModifierFlagsDefault ModifierFlags = 1 << 11 // Function/Class (export default declaration)
|
||||||
|
ModifierFlagsConst ModifierFlags = 1 << 12 // Const enum
|
||||||
|
ModifierFlagsIn ModifierFlags = 1 << 13 // Contravariance modifier
|
||||||
|
ModifierFlagsOut ModifierFlags = 1 << 14 // Covariance modifier
|
||||||
|
ModifierFlagsDecorator ModifierFlags = 1 << 15 // Contains a decorator
|
||||||
|
// JSDoc-only modifiers
|
||||||
|
ModifierFlagsDeprecated ModifierFlags = 1 << 16 // Deprecated tag
|
||||||
|
// Cache-only JSDoc-modifiers. Should match order of Syntactic/JSDoc modifiers, above.
|
||||||
|
ModifierFlagsJSDocPublic ModifierFlags = 1 << 23 // if this value changes, `selectEffectiveModifierFlags` must change accordingly
|
||||||
|
ModifierFlagsJSDocPrivate ModifierFlags = 1 << 24
|
||||||
|
ModifierFlagsJSDocProtected ModifierFlags = 1 << 25
|
||||||
|
ModifierFlagsJSDocReadonly ModifierFlags = 1 << 26
|
||||||
|
ModifierFlagsJSDocOverride ModifierFlags = 1 << 27
|
||||||
|
ModifierFlagsHasComputedJSDocModifiers ModifierFlags = 1 << 28 // Indicates the computed modifier flags include modifiers from JSDoc.
|
||||||
|
ModifierFlagsHasComputedFlags ModifierFlags = 1 << 29 // Modifier flags have been computed
|
||||||
|
|
||||||
|
ModifierFlagsSyntacticOrJSDocModifiers = ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsReadonly | ModifierFlagsOverride
|
||||||
|
ModifierFlagsSyntacticOnlyModifiers = ModifierFlagsExport | ModifierFlagsAmbient | ModifierFlagsAbstract | ModifierFlagsStatic | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault | ModifierFlagsConst | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsDecorator
|
||||||
|
ModifierFlagsSyntacticModifiers = ModifierFlagsSyntacticOrJSDocModifiers | ModifierFlagsSyntacticOnlyModifiers
|
||||||
|
ModifierFlagsJSDocCacheOnlyModifiers = ModifierFlagsJSDocPublic | ModifierFlagsJSDocPrivate | ModifierFlagsJSDocProtected | ModifierFlagsJSDocReadonly | ModifierFlagsJSDocOverride
|
||||||
|
ModifierFlagsJSDocOnlyModifiers = ModifierFlagsDeprecated
|
||||||
|
ModifierFlagsNonCacheOnlyModifiers = ModifierFlagsSyntacticOrJSDocModifiers | ModifierFlagsSyntacticOnlyModifiers | ModifierFlagsJSDocOnlyModifiers
|
||||||
|
|
||||||
|
ModifierFlagsAccessibilityModifier = ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected
|
||||||
|
// Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property.
|
||||||
|
ModifierFlagsParameterPropertyModifier = ModifierFlagsAccessibilityModifier | ModifierFlagsReadonly | ModifierFlagsOverride
|
||||||
|
ModifierFlagsNonPublicAccessibilityModifier = ModifierFlagsPrivate | ModifierFlagsProtected
|
||||||
|
|
||||||
|
ModifierFlagsTypeScriptModifier = ModifierFlagsAmbient | ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsReadonly | ModifierFlagsAbstract | ModifierFlagsConst | ModifierFlagsOverride | ModifierFlagsIn | ModifierFlagsOut
|
||||||
|
ModifierFlagsExportDefault = ModifierFlagsExport | ModifierFlagsDefault
|
||||||
|
ModifierFlagsAll = ModifierFlagsExport | ModifierFlagsAmbient | ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsStatic | ModifierFlagsReadonly | ModifierFlagsAbstract | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault | ModifierFlagsConst | ModifierFlagsDeprecated | ModifierFlagsOverride | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsDecorator
|
||||||
|
ModifierFlagsModifier = ModifierFlagsAll & ^ModifierFlagsDecorator
|
||||||
|
ModifierFlagsJavaScript = ModifierFlagsExport | ModifierFlagsStatic | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault
|
||||||
|
)
|
||||||
73
tools/tsgo/internal/ast/nodeflags.go
Normal file
73
tools/tsgo/internal/ast/nodeflags.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type NodeFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeFlagsNone NodeFlags = 0
|
||||||
|
NodeFlagsLet NodeFlags = 1 << 0 // Variable declaration
|
||||||
|
NodeFlagsConst NodeFlags = 1 << 1 // Variable declaration
|
||||||
|
NodeFlagsUsing NodeFlags = 1 << 2 // Variable declaration
|
||||||
|
NodeFlagsReparsed NodeFlags = 1 << 3 // Node was synthesized during parsing
|
||||||
|
NodeFlagsSynthesized NodeFlags = 1 << 4 // Node was synthesized during transformation
|
||||||
|
NodeFlagsOptionalChain NodeFlags = 1 << 5 // Chained MemberExpression rooted to a pseudo-OptionalExpression
|
||||||
|
NodeFlagsExportContext NodeFlags = 1 << 6 // Export context (initialized by binding)
|
||||||
|
NodeFlagsContainsThis NodeFlags = 1 << 7 // Interface contains references to "this"
|
||||||
|
NodeFlagsHasImplicitReturn NodeFlags = 1 << 8 // If function implicitly returns on one of codepaths (initialized by binding)
|
||||||
|
NodeFlagsHasExplicitReturn NodeFlags = 1 << 9 // If function has explicit reachable return on one of codepaths (initialized by binding)
|
||||||
|
NodeFlagsDisallowInContext NodeFlags = 1 << 10 // If node was parsed in a context where 'in-expressions' are not allowed
|
||||||
|
NodeFlagsYieldContext NodeFlags = 1 << 11 // If node was parsed in the 'yield' context created when parsing a generator
|
||||||
|
NodeFlagsDecoratorContext NodeFlags = 1 << 12 // If node was parsed as part of a decorator
|
||||||
|
NodeFlagsAwaitContext NodeFlags = 1 << 13 // If node was parsed in the 'await' context created when parsing an async function
|
||||||
|
NodeFlagsDisallowConditionalTypesContext NodeFlags = 1 << 14 // If node was parsed in a context where conditional types are not allowed
|
||||||
|
NodeFlagsThisNodeHasError NodeFlags = 1 << 15 // If the parser encountered an error when parsing the code that created this node
|
||||||
|
NodeFlagsJavaScriptFile NodeFlags = 1 << 16 // If node was parsed in a JavaScript
|
||||||
|
NodeFlagsThisNodeOrAnySubNodesHasError NodeFlags = 1 << 17 // If this node or any of its children had an error
|
||||||
|
NodeFlagsHasAsyncFunctions NodeFlags = 1 << 18 // If the file has async functions (initialized by binding)
|
||||||
|
// NodeFlagsHasAggregatedChildData is deprecated. Use `subtreeFacts` instead.
|
||||||
|
|
||||||
|
// These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid
|
||||||
|
// walking the tree if the flags are not set. However, these flags are just a approximation
|
||||||
|
// (hence why it's named "PossiblyContainsDynamicImport") because once set, the flags never get cleared.
|
||||||
|
// During editing, if a dynamic import is removed, incremental parsing will *NOT* clear this flag.
|
||||||
|
// This means that the tree will always be traversed during module resolution, or when looking for external module indicators.
|
||||||
|
// However, the removal operation should not occur often and in the case of the
|
||||||
|
// removal, it is likely that users will add the import anyway.
|
||||||
|
// The advantage of this approach is its simplicity. For the case of batch compilation,
|
||||||
|
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
|
||||||
|
NodeFlagsPossiblyContainsDynamicImport NodeFlags = 1 << 19
|
||||||
|
NodeFlagsPossiblyContainsImportMeta NodeFlags = 1 << 20
|
||||||
|
|
||||||
|
NodeFlagsHasJSDoc NodeFlags = 1 << 21 // If node has preceding JSDoc comment(s)
|
||||||
|
NodeFlagsJSDoc NodeFlags = 1 << 22 // If node was parsed inside jsdoc
|
||||||
|
NodeFlagsAmbient NodeFlags = 1 << 23 // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
|
||||||
|
NodeFlagsInWithStatement NodeFlags = 1 << 24 // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
|
||||||
|
NodeFlagsJsonFile NodeFlags = 1 << 25 // If node was parsed in a Json
|
||||||
|
NodeFlagsPossiblyContainsDeprecatedTag NodeFlags = 1 << 26 // Set during parse if comment text contains '@deprecated'; must confirm via JSDoc lookup
|
||||||
|
NodeFlagsUnreachable NodeFlags = 1 << 27 // If node is unreachable according to the binder
|
||||||
|
NodeFlagsReparserTransformedLiteral NodeFlags = 1 << 28 // If node was transformed during parsing, making its' naive text source not match the AST
|
||||||
|
|
||||||
|
NodeFlagsBlockScoped = NodeFlagsLet | NodeFlagsConst | NodeFlagsUsing
|
||||||
|
NodeFlagsConstant = NodeFlagsConst | NodeFlagsUsing
|
||||||
|
NodeFlagsAwaitUsing = NodeFlagsConst | NodeFlagsUsing // Variable declaration (NOTE: on a single node these flags would otherwise be mutually exclusive)
|
||||||
|
|
||||||
|
NodeFlagsReachabilityCheckFlags = NodeFlagsHasImplicitReturn | NodeFlagsHasExplicitReturn
|
||||||
|
NodeFlagsReachabilityAndEmitFlags = NodeFlagsReachabilityCheckFlags | NodeFlagsHasAsyncFunctions
|
||||||
|
|
||||||
|
// Parsing context flags
|
||||||
|
NodeFlagsContextFlags NodeFlags = NodeFlagsDisallowInContext | NodeFlagsDisallowConditionalTypesContext | NodeFlagsYieldContext | NodeFlagsDecoratorContext | NodeFlagsAwaitContext | NodeFlagsJavaScriptFile | NodeFlagsInWithStatement | NodeFlagsAmbient
|
||||||
|
|
||||||
|
// Exclude these flags when parsing a Type
|
||||||
|
NodeFlagsTypeExcludesFlags NodeFlags = NodeFlagsYieldContext | NodeFlagsAwaitContext
|
||||||
|
|
||||||
|
// Represents all flags that are potentially set once and
|
||||||
|
// never cleared on SourceFiles which get re-used in between incremental parses.
|
||||||
|
// See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`.
|
||||||
|
NodeFlagsPermanentlySetIncrementalFlags NodeFlags = NodeFlagsPossiblyContainsDynamicImport | NodeFlagsPossiblyContainsImportMeta
|
||||||
|
|
||||||
|
// The following flags repurpose other NodeFlags as different meanings for Identifier nodes
|
||||||
|
NodeFlagsIdentifierHasExtendedUnicodeEscape NodeFlags = NodeFlagsContainsThis // Indicates whether the identifier contains an extended unicode escape sequence
|
||||||
|
NodeFlagsIdentifierIsInJSDocNamespace NodeFlags = NodeFlagsHasAsyncFunctions // Indicates the identifier is the innermost name of a JSDoc namespace declaration
|
||||||
|
|
||||||
|
// The following flag repurposes other NodeFlags for ModuleDeclaration nodes
|
||||||
|
NodeFlagsNestedNamespace NodeFlags = NodeFlagsOptionalChain // If ModuleDeclaration is a nested namespace (e.g. inner part of A.B.C)
|
||||||
|
)
|
||||||
149
tools/tsgo/internal/ast/parseoptions.go
Normal file
149
tools/tsgo/internal/ast/parseoptions.go
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SourceFileParseOptions struct {
|
||||||
|
FileName string
|
||||||
|
Path tspath.Path
|
||||||
|
ExternalModuleIndicatorOptions ExternalModuleIndicatorOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExternalModuleIndicatorOptions struct {
|
||||||
|
JSX bool
|
||||||
|
Force bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetExternalModuleIndicatorOptions(fileName string, options *core.CompilerOptions, metadata SourceFileMetaData) ExternalModuleIndicatorOptions {
|
||||||
|
if tspath.IsDeclarationFileName(fileName) {
|
||||||
|
return ExternalModuleIndicatorOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch options.GetEmitModuleDetectionKind() {
|
||||||
|
case core.ModuleDetectionKindForce:
|
||||||
|
// All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule
|
||||||
|
return ExternalModuleIndicatorOptions{Force: true}
|
||||||
|
case core.ModuleDetectionKindLegacy:
|
||||||
|
// Files are modules if they have imports, exports, or import.meta
|
||||||
|
return ExternalModuleIndicatorOptions{}
|
||||||
|
case core.ModuleDetectionKindAuto:
|
||||||
|
// If module is nodenext or node16, all esm format files are modules
|
||||||
|
// If jsx is react-jsx or react-jsxdev then jsx tags force module-ness
|
||||||
|
// otherwise, the presence of import or export statments (or import.meta) implies module-ness
|
||||||
|
return ExternalModuleIndicatorOptions{
|
||||||
|
JSX: options.Jsx == core.JsxEmitReactJSX || options.Jsx == core.JsxEmitReactJSXDev,
|
||||||
|
Force: isFileForcedToBeModuleByFormat(fileName, options, metadata),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ExternalModuleIndicatorOptions{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isFileForcedToBeModuleByFormatExtensions = []string{tspath.ExtensionCjs, tspath.ExtensionCts, tspath.ExtensionMjs, tspath.ExtensionMts}
|
||||||
|
|
||||||
|
func isFileForcedToBeModuleByFormat(fileName string, options *core.CompilerOptions, metadata SourceFileMetaData) bool {
|
||||||
|
// Excludes declaration files - they still require an explicit `export {}` or the like
|
||||||
|
// for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files
|
||||||
|
// that aren't esm-mode (meaning not in a `type: module` scope).
|
||||||
|
if GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), metadata) == core.ModuleKindESNext || tspath.FileExtensionIsOneOf(fileName, isFileForcedToBeModuleByFormatExtensions) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetExternalModuleIndicator(file *SourceFile, opts ExternalModuleIndicatorOptions) {
|
||||||
|
file.ExternalModuleIndicator = getExternalModuleIndicator(file, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExternalModuleIndicator(file *SourceFile, opts ExternalModuleIndicatorOptions) *Node {
|
||||||
|
if file.ScriptKind == core.ScriptKindJSON {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if node := isFileProbablyExternalModule(file); node != nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
if file.IsDeclarationFile {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.JSX {
|
||||||
|
if node := isFileModuleFromUsingJSXTag(file); node != nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Force {
|
||||||
|
return file.AsNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFileProbablyExternalModule(sourceFile *SourceFile) *Node {
|
||||||
|
for _, statement := range sourceFile.Statements.Nodes {
|
||||||
|
if isAnExternalModuleIndicatorNode(statement) {
|
||||||
|
return statement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getImportMetaIfNecessary(sourceFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAnExternalModuleIndicatorNode(node *Node) bool {
|
||||||
|
return HasSyntacticModifier(node, ModifierFlagsExport) ||
|
||||||
|
IsImportEqualsDeclaration(node) && IsExternalModuleReference(node.AsImportEqualsDeclaration().ModuleReference) ||
|
||||||
|
IsImportDeclaration(node) || IsExportAssignment(node) || IsExportDeclaration(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getImportMetaIfNecessary(sourceFile *SourceFile) *Node {
|
||||||
|
if sourceFile.AsNode().Flags&NodeFlagsPossiblyContainsImportMeta != 0 {
|
||||||
|
return findChildNode(sourceFile.AsNode(), IsImportMeta)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findChildNode(root *Node, check func(*Node) bool) *Node {
|
||||||
|
var result *Node
|
||||||
|
var visit func(*Node) bool
|
||||||
|
visit = func(node *Node) bool {
|
||||||
|
if check(node) {
|
||||||
|
result = node
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return node.ForEachChild(visit)
|
||||||
|
}
|
||||||
|
visit(root)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFileModuleFromUsingJSXTag(file *SourceFile) *Node {
|
||||||
|
return walkTreeForJSXTags(file.AsNode())
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a somewhat unavoidable full tree walk to locate a JSX tag - `import.meta` requires the same,
|
||||||
|
// but we avoid that walk (or parts of it) if at all possible using the `PossiblyContainsImportMeta` node flag.
|
||||||
|
// Unfortunately, there's no `NodeFlag` space to do the same for JSX.
|
||||||
|
func walkTreeForJSXTags(node *Node) *Node {
|
||||||
|
var found *Node
|
||||||
|
|
||||||
|
var visitor func(node *Node) bool
|
||||||
|
visitor = func(node *Node) bool {
|
||||||
|
if found != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if node.SubtreeFacts()&SubtreeContainsJsx == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if IsJsxOpeningLikeElement(node) || IsJsxFragment(node) {
|
||||||
|
found = node
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return node.ForEachChild(visitor)
|
||||||
|
}
|
||||||
|
visitor(node)
|
||||||
|
|
||||||
|
return found
|
||||||
|
}
|
||||||
111
tools/tsgo/internal/ast/positionmap.go
Normal file
111
tools/tsgo/internal/ast/positionmap.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/stringutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PositionMap provides bidirectional mapping between UTF-8 byte offsets (used by Go)
|
||||||
|
// and UTF-16 code unit offsets (used by JavaScript/TypeScript).
|
||||||
|
//
|
||||||
|
// For ASCII-only text, the two are identical. For text containing non-ASCII characters,
|
||||||
|
// the offsets diverge because multi-byte UTF-8 sequences map to different numbers of
|
||||||
|
// UTF-16 code units:
|
||||||
|
// - U+0000..U+007F: 1 byte in UTF-8, 1 code unit in UTF-16
|
||||||
|
// - U+0080..U+07FF: 2 bytes in UTF-8, 1 code unit in UTF-16
|
||||||
|
// - U+0800..U+FFFF: 3 bytes in UTF-8, 1 code unit in UTF-16
|
||||||
|
// - U+10000..U+10FFFF: 4 bytes in UTF-8, 2 code units in UTF-16 (surrogate pair)
|
||||||
|
type PositionMap struct {
|
||||||
|
// asciiOnly is true if the text contains only ASCII characters,
|
||||||
|
// meaning UTF-8 byte offsets and UTF-16 code unit offsets are identical.
|
||||||
|
asciiOnly bool
|
||||||
|
// For each multi-byte character, we store:
|
||||||
|
// - the UTF-8 byte offset of the character
|
||||||
|
// - the cumulative delta (utf8Offset - utf16Offset) at that character
|
||||||
|
// This allows O(log n) conversion in either direction.
|
||||||
|
//
|
||||||
|
// entries[i].utf8Pos is the byte offset of the i-th multi-byte character.
|
||||||
|
// entries[i].delta is the total (utf8 - utf16) difference accumulated
|
||||||
|
// through and including the i-th multi-byte character.
|
||||||
|
entries []positionMapEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
type positionMapEntry struct {
|
||||||
|
utf8Pos int // UTF-8 byte offset AFTER this multi-byte character
|
||||||
|
delta int // cumulative (utf8 - utf16) offset difference after this character
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputePositionMap builds a PositionMap for the given text.
|
||||||
|
func ComputePositionMap(text string) *PositionMap {
|
||||||
|
pm := &PositionMap{}
|
||||||
|
delta := 0
|
||||||
|
for i := 0; i < len(text); {
|
||||||
|
b := text[i]
|
||||||
|
if b < utf8.RuneSelf {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, size := stringutil.DecodeJSStringRune(text[i:])
|
||||||
|
utf16Size := 1
|
||||||
|
if r >= 0x10000 {
|
||||||
|
utf16Size = 2
|
||||||
|
}
|
||||||
|
delta += size - utf16Size
|
||||||
|
pm.entries = append(pm.entries, positionMapEntry{utf8Pos: i + size, delta: delta})
|
||||||
|
i += size
|
||||||
|
}
|
||||||
|
pm.asciiOnly = len(pm.entries) == 0
|
||||||
|
return pm
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAsciiOnly returns true if the text is ASCII-only,
|
||||||
|
// meaning UTF-8 and UTF-16 offsets are identical.
|
||||||
|
func (pm *PositionMap) IsAsciiOnly() bool {
|
||||||
|
return pm.asciiOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF8ToUTF16 converts a UTF-8 byte offset to a UTF-16 code unit offset.
|
||||||
|
func (pm *PositionMap) UTF8ToUTF16(utf8Offset int) int {
|
||||||
|
if pm.asciiOnly {
|
||||||
|
return utf8Offset
|
||||||
|
}
|
||||||
|
// Binary search: find the last entry where utf8Pos <= utf8Offset
|
||||||
|
lo, hi := 0, len(pm.entries)
|
||||||
|
for lo < hi {
|
||||||
|
mid := lo + (hi-lo)/2
|
||||||
|
if pm.entries[mid].utf8Pos <= utf8Offset {
|
||||||
|
lo = mid + 1
|
||||||
|
} else {
|
||||||
|
hi = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lo == 0 {
|
||||||
|
// Before any multi-byte character
|
||||||
|
return utf8Offset
|
||||||
|
}
|
||||||
|
return utf8Offset - pm.entries[lo-1].delta
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF16ToUTF8 converts a UTF-16 code unit offset to a UTF-8 byte offset.
|
||||||
|
func (pm *PositionMap) UTF16ToUTF8(utf16Offset int) int {
|
||||||
|
if pm.asciiOnly {
|
||||||
|
return utf16Offset
|
||||||
|
}
|
||||||
|
// We need the last entry where (utf8Pos - delta) <= utf16Offset.
|
||||||
|
// (utf8Pos - delta) is the UTF-16 offset of that entry's character.
|
||||||
|
lo, hi := 0, len(pm.entries)
|
||||||
|
for lo < hi {
|
||||||
|
mid := lo + (hi-lo)/2
|
||||||
|
utf16Pos := pm.entries[mid].utf8Pos - pm.entries[mid].delta
|
||||||
|
if utf16Pos <= utf16Offset {
|
||||||
|
lo = mid + 1
|
||||||
|
} else {
|
||||||
|
hi = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lo == 0 {
|
||||||
|
return utf16Offset
|
||||||
|
}
|
||||||
|
return utf16Offset + pm.entries[lo-1].delta
|
||||||
|
}
|
||||||
225
tools/tsgo/internal/ast/positionmap_test.go
Normal file
225
tools/tsgo/internal/ast/positionmap_test.go
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
package ast_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/stringutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPositionMapASCII(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
text := "const x = 1;"
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
if !pm.IsAsciiOnly() {
|
||||||
|
t.Fatal("expected ASCII-only")
|
||||||
|
}
|
||||||
|
for i := 0; i <= len(text); i++ {
|
||||||
|
if got := pm.UTF8ToUTF16(i); got != i {
|
||||||
|
t.Errorf("UTF8ToUTF16(%d) = %d, want %d", i, got, i)
|
||||||
|
}
|
||||||
|
if got := pm.UTF16ToUTF8(i); got != i {
|
||||||
|
t.Errorf("UTF16ToUTF8(%d) = %d, want %d", i, got, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPositionMapTwoByte(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// "café" — é (U+00E9) is 2 bytes UTF-8, 1 code unit UTF-16
|
||||||
|
text := "const café = 1;\nconst x = 2;"
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
if pm.IsAsciiOnly() {
|
||||||
|
t.Fatal("expected non-ASCII")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything before é (byte offset 9) should be identity
|
||||||
|
for i := range 10 {
|
||||||
|
if got := pm.UTF8ToUTF16(i); got != i {
|
||||||
|
t.Errorf("before é: UTF8ToUTF16(%d) = %d, want %d", i, got, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// é starts at UTF-8 byte 9, UTF-16 offset 9: same
|
||||||
|
if got := pm.UTF8ToUTF16(9); got != 9 {
|
||||||
|
t.Errorf("at é: UTF8ToUTF16(9) = %d, want 9", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After é (byte 11 in UTF-8 = code unit 10 in UTF-16), delta is 1
|
||||||
|
// ' ' after café: UTF-8 byte 11, UTF-16 offset 10
|
||||||
|
if got := pm.UTF8ToUTF16(11); got != 10 {
|
||||||
|
t.Errorf("after é: UTF8ToUTF16(11) = %d, want 10", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'x' on second line: UTF-8 byte 23, UTF-16 offset 22
|
||||||
|
xUTF8 := strings.LastIndex(text, "x")
|
||||||
|
if got := pm.UTF8ToUTF16(xUTF8); got != xUTF8-1 {
|
||||||
|
t.Errorf("at x: UTF8ToUTF16(%d) = %d, want %d", xUTF8, got, xUTF8-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse: UTF-16 offset 22 should map to UTF-8 byte 23
|
||||||
|
xUTF16 := xUTF8 - 1
|
||||||
|
if got := pm.UTF16ToUTF8(xUTF16); got != xUTF8 {
|
||||||
|
t.Errorf("reverse at x: UTF16ToUTF8(%d) = %d, want %d", xUTF16, got, xUTF8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPositionMapFourByte(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// 🎉 (U+1F389) is 4 bytes UTF-8, 2 code units UTF-16
|
||||||
|
text := `const a = "🎉";` + "\nconst b = 2;"
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
if pm.IsAsciiOnly() {
|
||||||
|
t.Fatal("expected non-ASCII")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🎉 starts at byte 11 (after `const a = "`)
|
||||||
|
// UTF-8: bytes 11-14 (4 bytes), UTF-16: units 11-12 (2 code units)
|
||||||
|
// After 🎉: UTF-8 byte 15, UTF-16 offset 13. Delta = 2.
|
||||||
|
|
||||||
|
// 'b' on second line
|
||||||
|
bUTF8 := strings.LastIndex(text, "b")
|
||||||
|
bUTF16 := bUTF8 - 2 // delta of 2 from emoji
|
||||||
|
if got := pm.UTF8ToUTF16(bUTF8); got != bUTF16 {
|
||||||
|
t.Errorf("at b: UTF8ToUTF16(%d) = %d, want %d", bUTF8, got, bUTF16)
|
||||||
|
}
|
||||||
|
if got := pm.UTF16ToUTF8(bUTF16); got != bUTF8 {
|
||||||
|
t.Errorf("reverse at b: UTF16ToUTF8(%d) = %d, want %d", bUTF16, got, bUTF8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPositionMapMultipleNonASCII(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Mix of 2-byte and 4-byte characters
|
||||||
|
// "à" (U+00E0) = 2 bytes UTF-8, 1 code unit UTF-16 (delta +1)
|
||||||
|
// "🎉" (U+1F389) = 4 bytes UTF-8, 2 code units UTF-16 (delta +2)
|
||||||
|
text := "à🎉x"
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
|
||||||
|
// à: UTF-8 [0,2), UTF-16 [0,1)
|
||||||
|
// 🎉: UTF-8 [2,6), UTF-16 [1,3)
|
||||||
|
// x: UTF-8 [6,7), UTF-16 [3,4)
|
||||||
|
tests := []struct {
|
||||||
|
utf8 int
|
||||||
|
utf16 int
|
||||||
|
}{
|
||||||
|
{0, 0},
|
||||||
|
{2, 1}, // start of 🎉
|
||||||
|
{6, 3}, // x
|
||||||
|
{7, 4}, // end
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
if got := pm.UTF8ToUTF16(tt.utf8); got != tt.utf16 {
|
||||||
|
t.Errorf("UTF8ToUTF16(%d) = %d, want %d", tt.utf8, got, tt.utf16)
|
||||||
|
}
|
||||||
|
if got := pm.UTF16ToUTF8(tt.utf16); got != tt.utf8 {
|
||||||
|
t.Errorf("UTF16ToUTF8(%d) = %d, want %d", tt.utf16, got, tt.utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPositionMapLoneSurrogateSentinel(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
text := "a" + stringutil.EncodeJSStringRune(0xD800) + "b"
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
if pm.IsAsciiOnly() {
|
||||||
|
t.Fatal("expected non-ASCII")
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := pm.UTF8ToUTF16(len(text)); got != 3 {
|
||||||
|
t.Errorf("UTF8ToUTF16(%d) = %d, want 3", len(text), got)
|
||||||
|
}
|
||||||
|
if got := pm.UTF16ToUTF8(2); got != len(text)-1 {
|
||||||
|
t.Errorf("UTF16ToUTF8(2) = %d, want %d", got, len(text)-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPositionMapRoundtrip(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
text := "let café = \"🎉\"; // naïve"
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
|
||||||
|
// Convert every valid UTF-16 position to UTF-8 and back
|
||||||
|
utf16Len := pm.UTF8ToUTF16(len(text))
|
||||||
|
for i := 0; i <= utf16Len; i++ {
|
||||||
|
utf8Pos := pm.UTF16ToUTF8(i)
|
||||||
|
back := pm.UTF8ToUTF16(utf8Pos)
|
||||||
|
if back != i {
|
||||||
|
t.Errorf("roundtrip UTF16->UTF8->UTF16: %d -> %d -> %d", i, utf8Pos, back)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkComputePositionMap_ASCII(b *testing.B) {
|
||||||
|
// ~10KB of ASCII TypeScript-like code
|
||||||
|
line := "const variable = someFunction(argument1, argument2);\n"
|
||||||
|
text := strings.Repeat(line, 200)
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
ast.ComputePositionMap(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkComputePositionMap_NonASCII(b *testing.B) {
|
||||||
|
// Mix of ASCII and non-ASCII (comments with unicode)
|
||||||
|
line := "const café = \"héllo wörld 🎉\";\n"
|
||||||
|
text := strings.Repeat(line, 200)
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
ast.ComputePositionMap(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUTF8ToUTF16_ASCII(b *testing.B) {
|
||||||
|
line := "const variable = someFunction(argument1, argument2);\n"
|
||||||
|
text := strings.Repeat(line, 200)
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
positions := []int{0, 100, 500, 1000, 5000, len(text) - 1}
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
for _, p := range positions {
|
||||||
|
pm.UTF8ToUTF16(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUTF8ToUTF16_NonASCII(b *testing.B) {
|
||||||
|
line := "const café = \"héllo wörld 🎉\";\n"
|
||||||
|
text := strings.Repeat(line, 200)
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
positions := []int{0, 100, 500, 1000, 5000, len(text) - 1}
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
for _, p := range positions {
|
||||||
|
pm.UTF8ToUTF16(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUTF16ToUTF8_NonASCII(b *testing.B) {
|
||||||
|
line := "const café = \"héllo wörld 🎉\";\n"
|
||||||
|
text := strings.Repeat(line, 200)
|
||||||
|
pm := ast.ComputePositionMap(text)
|
||||||
|
utf16Len := pm.UTF8ToUTF16(len(text))
|
||||||
|
positions := []int{0, 100, 500, 1000, 3000, utf16Len - 1}
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
for _, p := range positions {
|
||||||
|
pm.UTF16ToUTF8(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkComputePositionMap_CheckerTS(b *testing.B) {
|
||||||
|
data, err := os.ReadFile("../../_submodules/TypeScript/src/compiler/checker.ts")
|
||||||
|
if err != nil {
|
||||||
|
b.Skip("checker.ts not available:", err)
|
||||||
|
}
|
||||||
|
text := string(data)
|
||||||
|
b.ResetTimer()
|
||||||
|
for range b.N {
|
||||||
|
ast.ComputePositionMap(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
717
tools/tsgo/internal/ast/precedence.go
Normal file
717
tools/tsgo/internal/ast/precedence.go
Normal file
@@ -0,0 +1,717 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OperatorPrecedence int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Expression:
|
||||||
|
// AssignmentExpression
|
||||||
|
// Expression `,` AssignmentExpression
|
||||||
|
OperatorPrecedenceComma OperatorPrecedence = iota
|
||||||
|
// NOTE: `Spread` is higher than `Comma` due to how it is parsed in |ElementList|
|
||||||
|
// SpreadElement:
|
||||||
|
// `...` AssignmentExpression
|
||||||
|
OperatorPrecedenceSpread
|
||||||
|
// AssignmentExpression:
|
||||||
|
// ConditionalExpression
|
||||||
|
// YieldExpression
|
||||||
|
// ArrowFunction
|
||||||
|
// AsyncArrowFunction
|
||||||
|
// LeftHandSideExpression `=` AssignmentExpression
|
||||||
|
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
||||||
|
//
|
||||||
|
// NOTE: AssignmentExpression is broken down into several precedences due to the requirements
|
||||||
|
// of the parenthesizer rules.
|
||||||
|
// AssignmentExpression: YieldExpression
|
||||||
|
// YieldExpression:
|
||||||
|
// `yield`
|
||||||
|
// `yield` AssignmentExpression
|
||||||
|
// `yield` `*` AssignmentExpression
|
||||||
|
OperatorPrecedenceYield
|
||||||
|
// AssignmentExpression: LeftHandSideExpression `=` AssignmentExpression
|
||||||
|
// AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression
|
||||||
|
// AssignmentOperator: one of
|
||||||
|
// `*=` `/=` `%=` `+=` `-=` `<<=` `>>=` `>>>=` `&=` `^=` `|=` `**=`
|
||||||
|
OperatorPrecedenceAssignment
|
||||||
|
// NOTE: `Conditional` is considered higher than `Assignment` here, but in reality they have
|
||||||
|
// the same precedence.
|
||||||
|
// AssignmentExpression: ConditionalExpression
|
||||||
|
// ConditionalExpression:
|
||||||
|
// ShortCircuitExpression
|
||||||
|
// ShortCircuitExpression `?` AssignmentExpression `:` AssignmentExpression
|
||||||
|
OperatorPrecedenceConditional
|
||||||
|
// LogicalORExpression:
|
||||||
|
// LogicalANDExpression
|
||||||
|
// LogicalORExpression `||` LogicalANDExpression
|
||||||
|
OperatorPrecedenceLogicalOR
|
||||||
|
// LogicalANDExpression:
|
||||||
|
// BitwiseORExpression
|
||||||
|
// LogicalANDExprerssion `&&` BitwiseORExpression
|
||||||
|
OperatorPrecedenceLogicalAND
|
||||||
|
// BitwiseORExpression:
|
||||||
|
// BitwiseXORExpression
|
||||||
|
// BitwiseORExpression `|` BitwiseXORExpression
|
||||||
|
OperatorPrecedenceBitwiseOR
|
||||||
|
// BitwiseXORExpression:
|
||||||
|
// BitwiseANDExpression
|
||||||
|
// BitwiseXORExpression `^` BitwiseANDExpression
|
||||||
|
OperatorPrecedenceBitwiseXOR
|
||||||
|
// BitwiseANDExpression:
|
||||||
|
// EqualityExpression
|
||||||
|
// BitwiseANDExpression `&` EqualityExpression
|
||||||
|
OperatorPrecedenceBitwiseAND
|
||||||
|
// EqualityExpression:
|
||||||
|
// RelationalExpression
|
||||||
|
// EqualityExpression `==` RelationalExpression
|
||||||
|
// EqualityExpression `!=` RelationalExpression
|
||||||
|
// EqualityExpression `===` RelationalExpression
|
||||||
|
// EqualityExpression `!==` RelationalExpression
|
||||||
|
OperatorPrecedenceEquality
|
||||||
|
// RelationalExpression:
|
||||||
|
// ShiftExpression
|
||||||
|
// RelationalExpression `<` ShiftExpression
|
||||||
|
// RelationalExpression `>` ShiftExpression
|
||||||
|
// RelationalExpression `<=` ShiftExpression
|
||||||
|
// RelationalExpression `>=` ShiftExpression
|
||||||
|
// RelationalExpression `instanceof` ShiftExpression
|
||||||
|
// RelationalExpression `in` ShiftExpression
|
||||||
|
// [+TypeScript] RelationalExpression `as` Type
|
||||||
|
OperatorPrecedenceRelational
|
||||||
|
// ShiftExpression:
|
||||||
|
// AdditiveExpression
|
||||||
|
// ShiftExpression `<<` AdditiveExpression
|
||||||
|
// ShiftExpression `>>` AdditiveExpression
|
||||||
|
// ShiftExpression `>>>` AdditiveExpression
|
||||||
|
OperatorPrecedenceShift
|
||||||
|
// AdditiveExpression:
|
||||||
|
// MultiplicativeExpression
|
||||||
|
// AdditiveExpression `+` MultiplicativeExpression
|
||||||
|
// AdditiveExpression `-` MultiplicativeExpression
|
||||||
|
OperatorPrecedenceAdditive
|
||||||
|
// MultiplicativeExpression:
|
||||||
|
// ExponentiationExpression
|
||||||
|
// MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
|
||||||
|
// MultiplicativeOperator: one of `*`, `/`, `%`
|
||||||
|
OperatorPrecedenceMultiplicative
|
||||||
|
// ExponentiationExpression:
|
||||||
|
// UnaryExpression
|
||||||
|
// UpdateExpression `**` ExponentiationExpression
|
||||||
|
OperatorPrecedenceExponentiation
|
||||||
|
// UnaryExpression:
|
||||||
|
// UpdateExpression
|
||||||
|
// `delete` UnaryExpression
|
||||||
|
// `void` UnaryExpression
|
||||||
|
// `typeof` UnaryExpression
|
||||||
|
// `+` UnaryExpression
|
||||||
|
// `-` UnaryExpression
|
||||||
|
// `~` UnaryExpression
|
||||||
|
// `!` UnaryExpression
|
||||||
|
// AwaitExpression
|
||||||
|
// UpdateExpression: // TODO: Do we need to investigate the precedence here?
|
||||||
|
// `++` UnaryExpression
|
||||||
|
// `--` UnaryExpression
|
||||||
|
OperatorPrecedenceUnary
|
||||||
|
// UpdateExpression:
|
||||||
|
// LeftHandSideExpression
|
||||||
|
// LeftHandSideExpression `++`
|
||||||
|
// LeftHandSideExpression `--`
|
||||||
|
OperatorPrecedenceUpdate
|
||||||
|
// LeftHandSideExpression:
|
||||||
|
// NewExpression
|
||||||
|
// NewExpression:
|
||||||
|
// MemberExpression
|
||||||
|
// `new` NewExpression
|
||||||
|
OperatorPrecedenceLeftHandSide
|
||||||
|
// LeftHandSideExpression:
|
||||||
|
// OptionalExpression
|
||||||
|
// OptionalExpression:
|
||||||
|
// MemberExpression OptionalChain
|
||||||
|
// CallExpression OptionalChain
|
||||||
|
// OptionalExpression OptionalChain
|
||||||
|
OperatorPrecedenceOptionalChain
|
||||||
|
// LeftHandSideExpression:
|
||||||
|
// CallExpression
|
||||||
|
// CallExpression:
|
||||||
|
// CoverCallExpressionAndAsyncArrowHead
|
||||||
|
// SuperCall
|
||||||
|
// ImportCall
|
||||||
|
// CallExpression Arguments
|
||||||
|
// CallExpression `[` Expression `]`
|
||||||
|
// CallExpression `.` IdentifierName
|
||||||
|
// CallExpression TemplateLiteral
|
||||||
|
// MemberExpression:
|
||||||
|
// PrimaryExpression
|
||||||
|
// MemberExpression `[` Expression `]`
|
||||||
|
// MemberExpression `.` IdentifierName
|
||||||
|
// MemberExpression TemplateLiteral
|
||||||
|
// SuperProperty
|
||||||
|
// MetaProperty
|
||||||
|
// `new` MemberExpression Arguments
|
||||||
|
OperatorPrecedenceMember
|
||||||
|
// TODO: JSXElement?
|
||||||
|
// PrimaryExpression:
|
||||||
|
// `this`
|
||||||
|
// IdentifierReference
|
||||||
|
// Literal
|
||||||
|
// ArrayLiteral
|
||||||
|
// ObjectLiteral
|
||||||
|
// FunctionExpression
|
||||||
|
// ClassExpression
|
||||||
|
// GeneratorExpression
|
||||||
|
// AsyncFunctionExpression
|
||||||
|
// AsyncGeneratorExpression
|
||||||
|
// RegularExpressionLiteral
|
||||||
|
// TemplateLiteral
|
||||||
|
OperatorPrecedencePrimary
|
||||||
|
// PrimaryExpression:
|
||||||
|
// CoverParenthesizedExpressionAndArrowParameterList
|
||||||
|
OperatorPrecedenceParentheses
|
||||||
|
OperatorPrecedenceLowest = OperatorPrecedenceComma
|
||||||
|
OperatorPrecedenceHighest = OperatorPrecedenceParentheses
|
||||||
|
OperatorPrecedenceDisallowComma = OperatorPrecedenceYield
|
||||||
|
// ShortCircuitExpression:
|
||||||
|
// LogicalORExpression
|
||||||
|
// CoalesceExpression
|
||||||
|
// CoalesceExpression:
|
||||||
|
// CoalesceExpressionHead `??` BitwiseORExpression
|
||||||
|
// CoalesceExpressionHead:
|
||||||
|
// CoalesceExpression
|
||||||
|
// BitwiseORExpression
|
||||||
|
OperatorPrecedenceCoalesce = OperatorPrecedenceLogicalOR
|
||||||
|
// -1 is lower than all other precedences. Returning it will cause binary expression
|
||||||
|
// parsing to stop.
|
||||||
|
OperatorPrecedenceInvalid OperatorPrecedence = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
func getOperator(expression *Expression) Kind {
|
||||||
|
switch expression.Kind {
|
||||||
|
case KindBinaryExpression:
|
||||||
|
return expression.AsBinaryExpression().OperatorToken.Kind
|
||||||
|
case KindPrefixUnaryExpression:
|
||||||
|
return expression.AsPrefixUnaryExpression().Operator
|
||||||
|
case KindPostfixUnaryExpression:
|
||||||
|
return expression.AsPostfixUnaryExpression().Operator
|
||||||
|
default:
|
||||||
|
return expression.Kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the precedence of an expression
|
||||||
|
func GetExpressionPrecedence(expression *Expression) OperatorPrecedence {
|
||||||
|
operator := getOperator(expression)
|
||||||
|
var flags OperatorPrecedenceFlags
|
||||||
|
if expression.Kind == KindNewExpression && expression.ArgumentList() == nil {
|
||||||
|
flags = OperatorPrecedenceFlagsNewWithoutArguments
|
||||||
|
} else if IsOptionalChain(expression) {
|
||||||
|
flags = OperatorPrecedenceFlagsOptionalChain
|
||||||
|
}
|
||||||
|
return GetOperatorPrecedence(expression.Kind, operator, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OperatorPrecedenceFlags int
|
||||||
|
|
||||||
|
const (
|
||||||
|
OperatorPrecedenceFlagsNone OperatorPrecedenceFlags = 0
|
||||||
|
OperatorPrecedenceFlagsNewWithoutArguments OperatorPrecedenceFlags = 1 << 0
|
||||||
|
OperatorPrecedenceFlagsOptionalChain OperatorPrecedenceFlags = 1 << 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gets the precedence of an operator
|
||||||
|
func GetOperatorPrecedence(nodeKind Kind, operatorKind Kind, flags OperatorPrecedenceFlags) OperatorPrecedence {
|
||||||
|
switch nodeKind {
|
||||||
|
case KindSpreadElement:
|
||||||
|
return OperatorPrecedenceSpread
|
||||||
|
case KindYieldExpression:
|
||||||
|
return OperatorPrecedenceYield
|
||||||
|
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
|
||||||
|
case KindArrowFunction:
|
||||||
|
return OperatorPrecedenceAssignment
|
||||||
|
case KindConditionalExpression:
|
||||||
|
return OperatorPrecedenceConditional
|
||||||
|
case KindBinaryExpression:
|
||||||
|
switch operatorKind {
|
||||||
|
case KindCommaToken:
|
||||||
|
return OperatorPrecedenceComma
|
||||||
|
|
||||||
|
case KindEqualsToken,
|
||||||
|
KindPlusEqualsToken,
|
||||||
|
KindMinusEqualsToken,
|
||||||
|
KindAsteriskAsteriskEqualsToken,
|
||||||
|
KindAsteriskEqualsToken,
|
||||||
|
KindSlashEqualsToken,
|
||||||
|
KindPercentEqualsToken,
|
||||||
|
KindLessThanLessThanEqualsToken,
|
||||||
|
KindGreaterThanGreaterThanEqualsToken,
|
||||||
|
KindGreaterThanGreaterThanGreaterThanEqualsToken,
|
||||||
|
KindAmpersandEqualsToken,
|
||||||
|
KindCaretEqualsToken,
|
||||||
|
KindBarEqualsToken,
|
||||||
|
KindBarBarEqualsToken,
|
||||||
|
KindAmpersandAmpersandEqualsToken,
|
||||||
|
KindQuestionQuestionEqualsToken:
|
||||||
|
return OperatorPrecedenceAssignment
|
||||||
|
|
||||||
|
default:
|
||||||
|
return GetBinaryOperatorPrecedence(operatorKind)
|
||||||
|
}
|
||||||
|
// TODO: Should prefix `++` and `--` be moved to the `Update` precedence?
|
||||||
|
case KindTypeAssertionExpression,
|
||||||
|
KindNonNullExpression,
|
||||||
|
KindPrefixUnaryExpression,
|
||||||
|
KindTypeOfExpression,
|
||||||
|
KindVoidExpression,
|
||||||
|
KindDeleteExpression,
|
||||||
|
KindAwaitExpression:
|
||||||
|
return OperatorPrecedenceUnary
|
||||||
|
|
||||||
|
case KindPostfixUnaryExpression:
|
||||||
|
return OperatorPrecedenceUpdate
|
||||||
|
|
||||||
|
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
|
||||||
|
case KindPropertyAccessExpression, KindElementAccessExpression:
|
||||||
|
if flags&OperatorPrecedenceFlagsOptionalChain != 0 {
|
||||||
|
return OperatorPrecedenceOptionalChain
|
||||||
|
}
|
||||||
|
return OperatorPrecedenceMember
|
||||||
|
|
||||||
|
case KindCallExpression:
|
||||||
|
if flags&OperatorPrecedenceFlagsOptionalChain != 0 {
|
||||||
|
return OperatorPrecedenceOptionalChain
|
||||||
|
}
|
||||||
|
return OperatorPrecedenceMember
|
||||||
|
|
||||||
|
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
|
||||||
|
case KindNewExpression:
|
||||||
|
if flags&OperatorPrecedenceFlagsNewWithoutArguments != 0 {
|
||||||
|
return OperatorPrecedenceLeftHandSide
|
||||||
|
}
|
||||||
|
return OperatorPrecedenceMember
|
||||||
|
|
||||||
|
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
|
||||||
|
case KindTaggedTemplateExpression, KindMetaProperty, KindExpressionWithTypeArguments:
|
||||||
|
return OperatorPrecedenceMember
|
||||||
|
|
||||||
|
case KindAsExpression,
|
||||||
|
KindSatisfiesExpression:
|
||||||
|
return OperatorPrecedenceRelational
|
||||||
|
|
||||||
|
case KindThisKeyword,
|
||||||
|
KindSuperKeyword,
|
||||||
|
KindImportKeyword,
|
||||||
|
KindIdentifier,
|
||||||
|
KindPrivateIdentifier,
|
||||||
|
KindNullKeyword,
|
||||||
|
KindTrueKeyword,
|
||||||
|
KindFalseKeyword,
|
||||||
|
KindNumericLiteral,
|
||||||
|
KindBigIntLiteral,
|
||||||
|
KindStringLiteral,
|
||||||
|
KindArrayLiteralExpression,
|
||||||
|
KindObjectLiteralExpression,
|
||||||
|
KindFunctionExpression,
|
||||||
|
KindClassExpression,
|
||||||
|
KindRegularExpressionLiteral,
|
||||||
|
KindNoSubstitutionTemplateLiteral,
|
||||||
|
KindTemplateExpression,
|
||||||
|
KindOmittedExpression,
|
||||||
|
KindJsxElement,
|
||||||
|
KindJsxSelfClosingElement,
|
||||||
|
KindJsxFragment,
|
||||||
|
KindMissingDeclaration:
|
||||||
|
return OperatorPrecedencePrimary
|
||||||
|
|
||||||
|
// !!! By necessity, this differs from the old compiler to support emit. consider backporting
|
||||||
|
case KindParenthesizedExpression:
|
||||||
|
return OperatorPrecedenceParentheses
|
||||||
|
|
||||||
|
default:
|
||||||
|
return OperatorPrecedenceInvalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the precedence of a binary operator
|
||||||
|
func GetBinaryOperatorPrecedence(operatorKind Kind) OperatorPrecedence {
|
||||||
|
switch operatorKind {
|
||||||
|
case KindQuestionQuestionToken:
|
||||||
|
return OperatorPrecedenceCoalesce
|
||||||
|
case KindBarBarToken:
|
||||||
|
return OperatorPrecedenceLogicalOR
|
||||||
|
case KindAmpersandAmpersandToken:
|
||||||
|
return OperatorPrecedenceLogicalAND
|
||||||
|
case KindBarToken:
|
||||||
|
return OperatorPrecedenceBitwiseOR
|
||||||
|
case KindCaretToken:
|
||||||
|
return OperatorPrecedenceBitwiseXOR
|
||||||
|
case KindAmpersandToken:
|
||||||
|
return OperatorPrecedenceBitwiseAND
|
||||||
|
case KindEqualsEqualsToken, KindExclamationEqualsToken, KindEqualsEqualsEqualsToken, KindExclamationEqualsEqualsToken:
|
||||||
|
return OperatorPrecedenceEquality
|
||||||
|
case KindLessThanToken, KindGreaterThanToken, KindLessThanEqualsToken, KindGreaterThanEqualsToken,
|
||||||
|
KindInstanceOfKeyword, KindInKeyword, KindAsKeyword, KindSatisfiesKeyword:
|
||||||
|
return OperatorPrecedenceRelational
|
||||||
|
case KindLessThanLessThanToken, KindGreaterThanGreaterThanToken, KindGreaterThanGreaterThanGreaterThanToken:
|
||||||
|
return OperatorPrecedenceShift
|
||||||
|
case KindPlusToken, KindMinusToken:
|
||||||
|
return OperatorPrecedenceAdditive
|
||||||
|
case KindAsteriskToken, KindSlashToken, KindPercentToken:
|
||||||
|
return OperatorPrecedenceMultiplicative
|
||||||
|
case KindAsteriskAsteriskToken:
|
||||||
|
return OperatorPrecedenceExponentiation
|
||||||
|
}
|
||||||
|
// -1 is lower than all other precedences. Returning it will cause binary expression
|
||||||
|
// parsing to stop.
|
||||||
|
return OperatorPrecedenceInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the leftmost expression of an expression, e.g. `a` in `a.b`, `a[b]`, `a++`, `a+b`, `a?b:c`, `a as B`, etc.
|
||||||
|
func GetLeftmostExpression(node *Expression, stopAtCallExpressions bool) *Expression {
|
||||||
|
for {
|
||||||
|
switch node.Kind {
|
||||||
|
case KindPostfixUnaryExpression:
|
||||||
|
node = node.AsPostfixUnaryExpression().Operand
|
||||||
|
continue
|
||||||
|
case KindBinaryExpression:
|
||||||
|
node = node.AsBinaryExpression().Left
|
||||||
|
continue
|
||||||
|
case KindConditionalExpression:
|
||||||
|
node = node.AsConditionalExpression().Condition
|
||||||
|
continue
|
||||||
|
case KindTaggedTemplateExpression:
|
||||||
|
node = node.AsTaggedTemplateExpression().Tag
|
||||||
|
continue
|
||||||
|
case KindCallExpression:
|
||||||
|
if stopAtCallExpressions {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case KindAsExpression,
|
||||||
|
KindElementAccessExpression,
|
||||||
|
KindPropertyAccessExpression,
|
||||||
|
KindNonNullExpression,
|
||||||
|
KindPartiallyEmittedExpression,
|
||||||
|
KindSatisfiesExpression:
|
||||||
|
node = node.Expression()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypePrecedence int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Conditional precedence (lowest)
|
||||||
|
//
|
||||||
|
// Type[Extends]:
|
||||||
|
// ConditionalTypeNode[?Extends]
|
||||||
|
//
|
||||||
|
// ConditionalTypeNode[Extends]:
|
||||||
|
// [~Extends] UnionTypeNode `extends` Type[+Extends] `?` Type[~Extends] `:` Type[~Extends]
|
||||||
|
//
|
||||||
|
TypePrecedenceConditional TypePrecedence = iota
|
||||||
|
|
||||||
|
// JSDoc precedence (optional and variadic types)
|
||||||
|
//
|
||||||
|
// JSDocType:
|
||||||
|
// `...`? Type `=`?
|
||||||
|
TypePrecedenceJSDoc
|
||||||
|
|
||||||
|
// Function precedence
|
||||||
|
//
|
||||||
|
// Type[Extends]:
|
||||||
|
// ConditionalTypeNode[?Extends]
|
||||||
|
// FunctionTypeNode[?Extends]
|
||||||
|
// ConstructorTypeNode[?Extends]
|
||||||
|
//
|
||||||
|
// ConditionalTypeNode[Extends]:
|
||||||
|
// UnionTypeNode
|
||||||
|
//
|
||||||
|
// FunctionTypeNode[Extends]:
|
||||||
|
// TypeParameters? ArrowParameters `=>` Type[?Extends]
|
||||||
|
//
|
||||||
|
// ConstructorTypeNode[Extends]:
|
||||||
|
// `abstract`? TypeParameters? ArrowParameters `=>` Type[?Extends]
|
||||||
|
//
|
||||||
|
TypePrecedenceFunction
|
||||||
|
|
||||||
|
// Union precedence
|
||||||
|
//
|
||||||
|
// UnionTypeNode:
|
||||||
|
// `|`? UnionTypeNoBar
|
||||||
|
//
|
||||||
|
// UnionTypeNoBar:
|
||||||
|
// IntersectionTypeNode
|
||||||
|
// UnionTypeNoBar `|` IntersectionTypeNode
|
||||||
|
//
|
||||||
|
TypePrecedenceUnion
|
||||||
|
|
||||||
|
// Intersection precedence
|
||||||
|
//
|
||||||
|
// IntersectionTypeNode:
|
||||||
|
// `&`? IntersectionTypeNoAmpersand
|
||||||
|
//
|
||||||
|
// IntersectionTypeNoAmpersand:
|
||||||
|
// TypeOperatorNode
|
||||||
|
// IntersectionTypeNoAmpersand `&` TypeOperatorNode
|
||||||
|
//
|
||||||
|
TypePrecedenceIntersection
|
||||||
|
|
||||||
|
// TypeOperatorNode precedence
|
||||||
|
//
|
||||||
|
// TypeOperatorNode:
|
||||||
|
// PostfixType
|
||||||
|
// InferTypeNode
|
||||||
|
// `keyof` TypeOperatorNode
|
||||||
|
// `unique` TypeOperatorNode
|
||||||
|
// `readonly` PostfixType
|
||||||
|
//
|
||||||
|
// InferTypeNode:
|
||||||
|
// `infer` BindingIdentifier
|
||||||
|
// `infer` BindingIdentifier `extends` Type[+Extends]
|
||||||
|
//
|
||||||
|
TypePrecedenceTypeOperator
|
||||||
|
|
||||||
|
// Postfix precedence
|
||||||
|
//
|
||||||
|
// PostfixType:
|
||||||
|
// NonArrayType
|
||||||
|
// OptionalTypeNode
|
||||||
|
// ArrayTypeNode
|
||||||
|
// IndexedAccessTypeNode
|
||||||
|
//
|
||||||
|
// OptionalTypeNode:
|
||||||
|
// PostfixType `?`
|
||||||
|
//
|
||||||
|
// ArrayTypeNode:
|
||||||
|
// PostfixType `[` `]`
|
||||||
|
//
|
||||||
|
// IndexedAccessTypeNode:
|
||||||
|
// PostfixType `[` Type[~Extends] `]`
|
||||||
|
//
|
||||||
|
TypePrecedencePostfix
|
||||||
|
|
||||||
|
// NonArray precedence (highest)
|
||||||
|
//
|
||||||
|
// NonArrayType:
|
||||||
|
// KeywordType
|
||||||
|
// LiteralTypeNode
|
||||||
|
// ThisTypeNode
|
||||||
|
// ImportType
|
||||||
|
// TypeQueryNode
|
||||||
|
// MappedTypeNode
|
||||||
|
// TypeLiteralNode
|
||||||
|
// TupleTypeNode
|
||||||
|
// ParenthesizedTypeNode
|
||||||
|
// TypePredicateNode
|
||||||
|
// TypeReferenceNode
|
||||||
|
// TemplateType
|
||||||
|
//
|
||||||
|
// KeywordType: one of
|
||||||
|
// `any` `unknown` `string` `number` `bigint`
|
||||||
|
// `symbol` `boolean` `undefined` `never` `object`
|
||||||
|
// `intrinsic` `void`
|
||||||
|
//
|
||||||
|
// LiteralTypeNode:
|
||||||
|
// StringLiteral
|
||||||
|
// NoSubstitutionTemplateLiteral
|
||||||
|
// NumericLiteral
|
||||||
|
// BigIntLiteral
|
||||||
|
// `-` NumericLiteral
|
||||||
|
// `-` BigIntLiteral
|
||||||
|
// `true`
|
||||||
|
// `false`
|
||||||
|
// `null`
|
||||||
|
//
|
||||||
|
// ThisTypeNode:
|
||||||
|
// `this`
|
||||||
|
//
|
||||||
|
// ImportType:
|
||||||
|
// `typeof`? `import` `(` Type[~Extends] `,`? `)` ImportTypeQualifier? TypeArguments?
|
||||||
|
// `typeof`? `import` `(` Type[~Extends] `,` ImportTypeAttributes `,`? `)` ImportTypeQualifier? TypeArguments?
|
||||||
|
//
|
||||||
|
// ImportTypeQualifier:
|
||||||
|
// `.` EntityName
|
||||||
|
//
|
||||||
|
// ImportTypeAttributes:
|
||||||
|
// `{` `with` `:` ImportAttributes `,`? `}`
|
||||||
|
//
|
||||||
|
// TypeQueryNode:
|
||||||
|
//
|
||||||
|
// MappedTypeNode:
|
||||||
|
// `{` MappedTypePrefix? MappedTypePropertyName MappedTypeSuffix? `:` Type[~Extends] `;` `}`
|
||||||
|
//
|
||||||
|
// MappedTypePrefix:
|
||||||
|
// `readonly`
|
||||||
|
// `+` `readonly`
|
||||||
|
// `-` `readonly`
|
||||||
|
//
|
||||||
|
// MappedTypePropertyName:
|
||||||
|
// `[` BindingIdentifier `in` Type[~Extends] `]`
|
||||||
|
// `[` BindingIdentifier `in` Type[~Extends] `as` Type[~Extends] `]`
|
||||||
|
//
|
||||||
|
// MappedTypeSuffix:
|
||||||
|
// `?`
|
||||||
|
// `+` `?`
|
||||||
|
// `-` `?`
|
||||||
|
//
|
||||||
|
// TypeLiteralNode:
|
||||||
|
// `{` TypeElementList `}`
|
||||||
|
//
|
||||||
|
// TypeElementList:
|
||||||
|
// [empty]
|
||||||
|
// TypeElementList TypeElement
|
||||||
|
//
|
||||||
|
// TypeElement:
|
||||||
|
// PropertySignatureDeclaration
|
||||||
|
// MethodSignatureDeclaration
|
||||||
|
// IndexSignatureDeclaration
|
||||||
|
// CallSignatureDeclaration
|
||||||
|
// ConstructSignatureDeclaration
|
||||||
|
//
|
||||||
|
// PropertySignatureDeclaration:
|
||||||
|
// PropertyName `?`? TypeAnnotation? `;`
|
||||||
|
//
|
||||||
|
// MethodSignatureDeclaration:
|
||||||
|
// PropertyName `?`? TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;`
|
||||||
|
// `get` PropertyName TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;` // GetAccessorDeclaration
|
||||||
|
// `set` PropertyName TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;` // SetAccessorDeclaration
|
||||||
|
//
|
||||||
|
// IndexSignatureDeclaration:
|
||||||
|
// `[` IdentifierName`]` TypeAnnotation `;`
|
||||||
|
//
|
||||||
|
// CallSignatureDeclaration:
|
||||||
|
// TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;`
|
||||||
|
//
|
||||||
|
// ConstructSignatureDeclaration:
|
||||||
|
// `new` TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;`
|
||||||
|
//
|
||||||
|
// TupleTypeNode:
|
||||||
|
// `[` `]`
|
||||||
|
// `[` NamedTupleElementTypes `,`? `]`
|
||||||
|
// `[` TupleElementTypes `,`? `]`
|
||||||
|
//
|
||||||
|
// NamedTupleElementTypes:
|
||||||
|
// NamedTupleMember
|
||||||
|
// NamedTupleElementTypes `,` NamedTupleMember
|
||||||
|
//
|
||||||
|
// NamedTupleMember:
|
||||||
|
// IdentifierName `?`? `:` Type[~Extends]
|
||||||
|
// `...` IdentifierName `:` Type[~Extends]
|
||||||
|
//
|
||||||
|
// TupleElementTypes:
|
||||||
|
// TupleElementType
|
||||||
|
// TupleElementTypes `,` TupleElementType
|
||||||
|
//
|
||||||
|
// TupleElementType:
|
||||||
|
// Type[~Extends]
|
||||||
|
// OptionalTypeNode
|
||||||
|
// RestTypeNode
|
||||||
|
//
|
||||||
|
// RestTypeNode:
|
||||||
|
// `...` Type[~Extends]
|
||||||
|
//
|
||||||
|
// ParenthesizedTypeNode:
|
||||||
|
// `(` Type[~Extends] `)`
|
||||||
|
//
|
||||||
|
// TypePredicateNode:
|
||||||
|
// `asserts`? TypePredicateParameterName
|
||||||
|
// `asserts`? TypePredicateParameterName `is` Type[~Extends]
|
||||||
|
//
|
||||||
|
// TypePredicateParameterName:
|
||||||
|
// `this`
|
||||||
|
// IdentifierReference
|
||||||
|
//
|
||||||
|
// TypeReferenceNode:
|
||||||
|
// EntityName TypeArguments?
|
||||||
|
//
|
||||||
|
// TemplateType:
|
||||||
|
// TemplateHead Type[~Extends] TemplateTypeSpans
|
||||||
|
//
|
||||||
|
// TemplateTypeSpans:
|
||||||
|
// TemplateTail
|
||||||
|
// TemplateTypeMiddleList TemplateTail
|
||||||
|
//
|
||||||
|
// TemplateTypeMiddleList:
|
||||||
|
// TemplateMiddle Type[~Extends]
|
||||||
|
// TemplateTypeMiddleList TemplateMiddle Type[~Extends]
|
||||||
|
//
|
||||||
|
// TypeArguments:
|
||||||
|
// `<` TypeArgumentList `,`? `>`
|
||||||
|
//
|
||||||
|
// TypeArgumentList:
|
||||||
|
// Type[~Extends]
|
||||||
|
// TypeArgumentList `,` Type[~Extends]
|
||||||
|
//
|
||||||
|
TypePrecedenceNonArray
|
||||||
|
|
||||||
|
TypePrecedenceLowest = TypePrecedenceConditional
|
||||||
|
TypePrecedenceHighest = TypePrecedenceNonArray
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gets the precedence of a TypeNode
|
||||||
|
func GetTypeNodePrecedence(n *TypeNode) TypePrecedence {
|
||||||
|
switch n.Kind {
|
||||||
|
case KindConditionalType:
|
||||||
|
return TypePrecedenceConditional
|
||||||
|
case KindJSDocOptionalType, KindJSDocVariadicType:
|
||||||
|
return TypePrecedenceJSDoc
|
||||||
|
case KindFunctionType, KindConstructorType:
|
||||||
|
return TypePrecedenceFunction
|
||||||
|
case KindUnionType:
|
||||||
|
return TypePrecedenceUnion
|
||||||
|
case KindIntersectionType:
|
||||||
|
return TypePrecedenceIntersection
|
||||||
|
case KindTypeOperator:
|
||||||
|
return TypePrecedenceTypeOperator
|
||||||
|
case KindInferType:
|
||||||
|
if n.AsInferTypeNode().TypeParameter.AsTypeParameterDeclaration().Constraint != nil {
|
||||||
|
// `infer T extends U` must be treated as FunctionTypeNode precedence as the `extends` clause eagerly consumes
|
||||||
|
// TypeNode
|
||||||
|
return TypePrecedenceFunction
|
||||||
|
}
|
||||||
|
return TypePrecedenceTypeOperator
|
||||||
|
case KindIndexedAccessType, KindArrayType, KindOptionalType:
|
||||||
|
return TypePrecedencePostfix
|
||||||
|
case KindTypeQuery:
|
||||||
|
// TypeQueryNode is actually a NonArrayType, but we treat it as TypeOperatorNode
|
||||||
|
// precedence so that it is parenthesized when used in a PostfixType
|
||||||
|
// context (e.g., `(typeof C)[]` instead of `typeof C[]`)
|
||||||
|
return TypePrecedenceTypeOperator
|
||||||
|
case KindAnyKeyword,
|
||||||
|
KindUnknownKeyword,
|
||||||
|
KindStringKeyword,
|
||||||
|
KindNumberKeyword,
|
||||||
|
KindBigIntKeyword,
|
||||||
|
KindSymbolKeyword,
|
||||||
|
KindBooleanKeyword,
|
||||||
|
KindUndefinedKeyword,
|
||||||
|
KindNeverKeyword,
|
||||||
|
KindObjectKeyword,
|
||||||
|
KindIntrinsicKeyword,
|
||||||
|
KindVoidKeyword,
|
||||||
|
KindJSDocAllType,
|
||||||
|
KindJSDocNullableType,
|
||||||
|
KindJSDocNonNullableType,
|
||||||
|
KindLiteralType,
|
||||||
|
KindTypePredicate,
|
||||||
|
KindTypeReference,
|
||||||
|
KindTypeLiteral,
|
||||||
|
KindTupleType,
|
||||||
|
KindRestType,
|
||||||
|
KindParenthesizedType,
|
||||||
|
KindThisType,
|
||||||
|
KindMappedType,
|
||||||
|
KindNamedTupleMember,
|
||||||
|
KindTemplateLiteralType,
|
||||||
|
KindImportType,
|
||||||
|
// These occur in pseudo-types like `f<T>.C`, where `f` is a generic function and `C` is a local type
|
||||||
|
KindPropertyAccessExpression,
|
||||||
|
KindExpressionWithTypeArguments:
|
||||||
|
return TypePrecedenceNonArray
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unhandled TypeNode: %v", n.Kind))
|
||||||
|
}
|
||||||
|
}
|
||||||
133
tools/tsgo/internal/ast/subtreefacts.go
Normal file
133
tools/tsgo/internal/ast/subtreefacts.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SubtreeFacts uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Facts
|
||||||
|
// - Flags used to indicate that a node or subtree contains syntax relevant to a specific transform
|
||||||
|
|
||||||
|
SubtreeContainsTypeScript SubtreeFacts = 1 << iota
|
||||||
|
SubtreeContainsJsx
|
||||||
|
SubtreeContainsESDecorators
|
||||||
|
SubtreeContainsUsing
|
||||||
|
SubtreeContainsClassStaticBlocks
|
||||||
|
SubtreeContainsESClassFields
|
||||||
|
SubtreeContainsLogicalAssignments
|
||||||
|
SubtreeContainsNullishCoalescing
|
||||||
|
SubtreeContainsOptionalChaining
|
||||||
|
SubtreeContainsMissingCatchClauseVariable
|
||||||
|
SubtreeContainsESObjectRestOrSpread // subtree has a `...` somewhere inside it, never cleared
|
||||||
|
SubtreeContainsForAwaitOrAsyncGenerator
|
||||||
|
SubtreeContainsAnyAwait
|
||||||
|
SubtreeContainsExponentiationOperator
|
||||||
|
|
||||||
|
// Markers
|
||||||
|
// - Flags used to indicate that a node or subtree contains a particular kind of syntax.
|
||||||
|
|
||||||
|
SubtreeContainsLexicalThis
|
||||||
|
SubtreeContainsLexicalSuper
|
||||||
|
SubtreeContainsRestOrSpread // marker on any `...` - cleared on binding pattern exit
|
||||||
|
SubtreeContainsObjectRestOrSpread // marker on any `{...x}` - cleared on most scope exits
|
||||||
|
SubtreeContainsAwait
|
||||||
|
SubtreeContainsDynamicImport
|
||||||
|
SubtreeContainsClassFields
|
||||||
|
SubtreeContainsDecorators
|
||||||
|
SubtreeContainsIdentifier
|
||||||
|
SubtreeContainsPrivateIdentifierInExpression
|
||||||
|
SubtreeContainsInvalidTemplateEscape
|
||||||
|
|
||||||
|
SubtreeFactsComputed // NOTE: This should always be last
|
||||||
|
SubtreeFactsNone SubtreeFacts = 0
|
||||||
|
|
||||||
|
// Aliases (unused, for documentation purposes only - correspond to combinations in transformers/estransforms/definitions.go)
|
||||||
|
|
||||||
|
SubtreeContainsESNext = SubtreeContainsESDecorators | SubtreeContainsUsing
|
||||||
|
SubtreeContainsES2022 = SubtreeContainsClassStaticBlocks | SubtreeContainsESClassFields
|
||||||
|
SubtreeContainsES2021 = SubtreeContainsLogicalAssignments
|
||||||
|
SubtreeContainsES2020 = SubtreeContainsNullishCoalescing | SubtreeContainsOptionalChaining
|
||||||
|
SubtreeContainsES2019 = SubtreeContainsMissingCatchClauseVariable
|
||||||
|
SubtreeContainsES2018 = SubtreeContainsESObjectRestOrSpread | SubtreeContainsForAwaitOrAsyncGenerator | SubtreeContainsInvalidTemplateEscape
|
||||||
|
SubtreeContainsES2017 = SubtreeContainsAnyAwait
|
||||||
|
SubtreeContainsES2016 = SubtreeContainsExponentiationOperator
|
||||||
|
|
||||||
|
// Scope Exclusions
|
||||||
|
// - Bitmasks that exclude flags from propagating out of a specific context
|
||||||
|
// into the subtree flags of their container.
|
||||||
|
|
||||||
|
SubtreeExclusionsNode = SubtreeFactsComputed
|
||||||
|
SubtreeExclusionsEraseable = ^SubtreeContainsTypeScript
|
||||||
|
SubtreeExclusionsOuterExpression = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsPropertyAccess = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsElementAccess = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsArrowFunction = SubtreeExclusionsNode | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsFunction = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsConstructor = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsMethod = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsAccessor = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsProperty = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper
|
||||||
|
SubtreeExclusionsClass = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsModule = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper
|
||||||
|
SubtreeExclusionsObjectLiteral = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsArrayLiteral = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsCall = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsNew = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsVariableDeclarationList = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsParameter = SubtreeExclusionsNode
|
||||||
|
SubtreeExclusionsCatchClause = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread
|
||||||
|
SubtreeExclusionsBindingPattern = SubtreeExclusionsNode | SubtreeContainsRestOrSpread
|
||||||
|
|
||||||
|
// Masks
|
||||||
|
// - Additional bitmasks
|
||||||
|
|
||||||
|
SubtreeContainsLexicalThisOrSuper = SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper
|
||||||
|
)
|
||||||
|
|
||||||
|
func propagateEraseableSyntaxListSubtreeFacts(children *TypeArgumentList) SubtreeFacts {
|
||||||
|
return core.IfElse(children != nil, SubtreeContainsTypeScript, SubtreeFactsNone)
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagateEraseableSyntaxSubtreeFacts(child *TypeNode) SubtreeFacts {
|
||||||
|
return core.IfElse(child != nil, SubtreeContainsTypeScript, SubtreeFactsNone)
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagateObjectBindingElementSubtreeFacts(child *BindingElementNode) SubtreeFacts {
|
||||||
|
facts := propagateSubtreeFacts(child)
|
||||||
|
if facts&SubtreeContainsRestOrSpread != 0 {
|
||||||
|
facts &^= SubtreeContainsRestOrSpread
|
||||||
|
facts |= SubtreeContainsObjectRestOrSpread | SubtreeContainsESObjectRestOrSpread
|
||||||
|
}
|
||||||
|
return facts
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagateBindingElementSubtreeFacts(child *BindingElementNode) SubtreeFacts {
|
||||||
|
return propagateSubtreeFacts(child) & ^SubtreeContainsRestOrSpread
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagateSubtreeFacts(child *Node) SubtreeFacts {
|
||||||
|
if child == nil {
|
||||||
|
return SubtreeFactsNone
|
||||||
|
}
|
||||||
|
return child.propagateSubtreeFacts()
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagateNodeListSubtreeFacts(children *NodeList, propagate func(*Node) SubtreeFacts) SubtreeFacts {
|
||||||
|
if children == nil {
|
||||||
|
return SubtreeFactsNone
|
||||||
|
}
|
||||||
|
facts := SubtreeFactsNone
|
||||||
|
for _, child := range children.Nodes {
|
||||||
|
facts |= propagate(child)
|
||||||
|
}
|
||||||
|
return facts
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagateModifierListSubtreeFacts(children *ModifierList) SubtreeFacts {
|
||||||
|
if children == nil {
|
||||||
|
return SubtreeFactsNone
|
||||||
|
}
|
||||||
|
return propagateNodeListSubtreeFacts(&children.NodeList, propagateSubtreeFacts)
|
||||||
|
}
|
||||||
103
tools/tsgo/internal/ast/symbol.go
Normal file
103
tools/tsgo/internal/ast/symbol.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Symbol
|
||||||
|
|
||||||
|
type Symbol struct {
|
||||||
|
Flags SymbolFlags
|
||||||
|
CheckFlags CheckFlags // Non-zero only in transient symbols created by Checker
|
||||||
|
Name string
|
||||||
|
Declarations []*Node
|
||||||
|
ValueDeclaration *Node
|
||||||
|
Members SymbolTable
|
||||||
|
Exports SymbolTable
|
||||||
|
id atomic.Uint64
|
||||||
|
Parent *Symbol
|
||||||
|
ExportSymbol *Symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Symbol) IsExternalModule() bool {
|
||||||
|
return s.Flags&SymbolFlagsModule != 0 && len(s.Name) > 0 && s.Name[0] == '"'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Symbol) IsStatic() bool {
|
||||||
|
if s.ValueDeclaration == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
modifierFlags := s.ValueDeclaration.ModifierFlags()
|
||||||
|
return modifierFlags&ModifierFlagsStatic != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// See comment on `declareModuleMember` in `binder.go`.
|
||||||
|
func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags {
|
||||||
|
if s.ExportSymbol != nil {
|
||||||
|
return s.Flags | s.ExportSymbol.Flags
|
||||||
|
}
|
||||||
|
return s.Flags
|
||||||
|
}
|
||||||
|
|
||||||
|
// SymbolTable
|
||||||
|
|
||||||
|
type SymbolTable map[string]*Symbol
|
||||||
|
|
||||||
|
const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName
|
||||||
|
|
||||||
|
const (
|
||||||
|
InternalSymbolNameCall = InternalSymbolNamePrefix + "call" // Call signatures
|
||||||
|
InternalSymbolNameConstructor = InternalSymbolNamePrefix + "constructor" // Constructor implementations
|
||||||
|
InternalSymbolNameNew = InternalSymbolNamePrefix + "new" // Constructor signatures
|
||||||
|
InternalSymbolNameIndex = InternalSymbolNamePrefix + "index" // Index signatures
|
||||||
|
InternalSymbolNameExportStar = InternalSymbolNamePrefix + "export" // Module export * declarations
|
||||||
|
InternalSymbolNameGlobal = InternalSymbolNamePrefix + "global" // Global self-reference
|
||||||
|
InternalSymbolNameMissing = InternalSymbolNamePrefix + "missing" // Indicates missing symbol
|
||||||
|
InternalSymbolNameType = InternalSymbolNamePrefix + "type" // Anonymous type literal symbol
|
||||||
|
InternalSymbolNameObject = InternalSymbolNamePrefix + "object" // Anonymous object literal declaration
|
||||||
|
InternalSymbolNameJSXAttributes = InternalSymbolNamePrefix + "jsxAttributes" // Anonymous JSX attributes object literal declaration
|
||||||
|
InternalSymbolNameClass = InternalSymbolNamePrefix + "class" // Unnamed class expression
|
||||||
|
InternalSymbolNameFunction = InternalSymbolNamePrefix + "function" // Unnamed function expression
|
||||||
|
InternalSymbolNameComputed = InternalSymbolNamePrefix + "computed" // Computed property name declaration with dynamic name
|
||||||
|
InternalSymbolNameAssignmentDeclaration = InternalSymbolNamePrefix + "assignment" // Assignment declarations
|
||||||
|
InternalSymbolNameInstantiationExpression = InternalSymbolNamePrefix + "instantiationExpression" // Instantiation expressions
|
||||||
|
InternalSymbolNameImportAttributes = InternalSymbolNamePrefix + "importAttributes"
|
||||||
|
InternalSymbolNameExportEquals = "export=" // Export assignment symbol
|
||||||
|
InternalSymbolNameDefault = "default" // Default export symbol (technically not wholly internal, but included here for usability)
|
||||||
|
InternalSymbolNameThis = "this"
|
||||||
|
InternalSymbolNameModuleExports = "module.exports"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SymbolName(symbol *Symbol) string {
|
||||||
|
if symbol.ValueDeclaration != nil && IsPrivateIdentifierClassElementDeclaration(symbol.ValueDeclaration) {
|
||||||
|
return symbol.ValueDeclaration.Name().Text()
|
||||||
|
}
|
||||||
|
return symbol.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapeAllInternalSymbolNames replaces internal symbol name markers ("\xFE") with "__".
|
||||||
|
func EscapeAllInternalSymbolNames(name string) string {
|
||||||
|
return strings.ReplaceAll(name, InternalSymbolNamePrefix, "__")
|
||||||
|
}
|
||||||
|
|
||||||
|
func EscapeInternalSymbolName(name string) string {
|
||||||
|
if rest, ok := strings.CutPrefix(name, InternalSymbolNamePrefix); ok {
|
||||||
|
return "__" + rest
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapeSymbolName converts a binder symbol name into its escaped "__String"
|
||||||
|
// form. Internal names (prefixed with the "\xFE" sentinel) become "__"-prefixed,
|
||||||
|
// and user names that already begin with "__" gain an extra leading underscore
|
||||||
|
// so they can be distinguished from internal names.
|
||||||
|
func EscapeSymbolName(name string) string {
|
||||||
|
if rest, ok := strings.CutPrefix(name, InternalSymbolNamePrefix); ok {
|
||||||
|
return "__" + rest
|
||||||
|
}
|
||||||
|
if len(name) >= 2 && name[0] == '_' && name[1] == '_' {
|
||||||
|
return "_" + name
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
86
tools/tsgo/internal/ast/symbolflags.go
Normal file
86
tools/tsgo/internal/ast/symbolflags.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
// SymbolFlags
|
||||||
|
|
||||||
|
type SymbolFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
SymbolFlagsNone SymbolFlags = 0
|
||||||
|
SymbolFlagsFunctionScopedVariable SymbolFlags = 1 << 0 // Variable (var) or parameter
|
||||||
|
SymbolFlagsBlockScopedVariable SymbolFlags = 1 << 1 // A block-scoped variable (let or const)
|
||||||
|
SymbolFlagsProperty SymbolFlags = 1 << 2 // Property or enum member
|
||||||
|
SymbolFlagsEnumMember SymbolFlags = 1 << 3 // Enum member
|
||||||
|
SymbolFlagsFunction SymbolFlags = 1 << 4 // Function
|
||||||
|
SymbolFlagsClass SymbolFlags = 1 << 5 // Class
|
||||||
|
SymbolFlagsInterface SymbolFlags = 1 << 6 // Interface
|
||||||
|
SymbolFlagsConstEnum SymbolFlags = 1 << 7 // Const enum
|
||||||
|
SymbolFlagsRegularEnum SymbolFlags = 1 << 8 // Enum
|
||||||
|
SymbolFlagsValueModule SymbolFlags = 1 << 9 // Instantiated module
|
||||||
|
SymbolFlagsNamespaceModule SymbolFlags = 1 << 10 // Uninstantiated module
|
||||||
|
SymbolFlagsTypeLiteral SymbolFlags = 1 << 11 // Type Literal or mapped type
|
||||||
|
SymbolFlagsObjectLiteral SymbolFlags = 1 << 12 // Object Literal
|
||||||
|
SymbolFlagsMethod SymbolFlags = 1 << 13 // Method
|
||||||
|
SymbolFlagsConstructor SymbolFlags = 1 << 14 // Constructor
|
||||||
|
SymbolFlagsGetAccessor SymbolFlags = 1 << 15 // Get accessor
|
||||||
|
SymbolFlagsSetAccessor SymbolFlags = 1 << 16 // Set accessor
|
||||||
|
SymbolFlagsSignature SymbolFlags = 1 << 17 // Call, construct, or index signature
|
||||||
|
SymbolFlagsTypeParameter SymbolFlags = 1 << 18 // Type parameter
|
||||||
|
SymbolFlagsTypeAlias SymbolFlags = 1 << 19 // Type alias
|
||||||
|
SymbolFlagsExportValue SymbolFlags = 1 << 20 // Exported value marker (see comment in declareModuleMember in binder)
|
||||||
|
SymbolFlagsAlias SymbolFlags = 1 << 21 // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
|
||||||
|
SymbolFlagsPrototype SymbolFlags = 1 << 22 // Prototype property (no source representation)
|
||||||
|
SymbolFlagsExportStar SymbolFlags = 1 << 23 // Export * declaration
|
||||||
|
SymbolFlagsOptional SymbolFlags = 1 << 24 // Optional property
|
||||||
|
SymbolFlagsTransient SymbolFlags = 1 << 25 // Transient symbol (created during type check)
|
||||||
|
SymbolFlagsAssignment SymbolFlags = 1 << 26 // Assignment to property on function acting as declaration (eg `func.prop = 1`)
|
||||||
|
SymbolFlagsModuleExports SymbolFlags = 1 << 27 // Symbol for CommonJS `module` of `module.exports`
|
||||||
|
SymbolFlagsConstEnumOnlyModule SymbolFlags = 1 << 28 // Module contains only const enums or other modules with only const enums
|
||||||
|
SymbolFlagsReplaceableByMethod SymbolFlags = 1 << 29
|
||||||
|
SymbolFlagsGlobalLookup SymbolFlags = 1 << 30 // Flag to signal this is a global lookup
|
||||||
|
SymbolFlagsAll SymbolFlags = 1<<30 - 1 // All flags except SymbolFlagsGlobalLookup
|
||||||
|
|
||||||
|
SymbolFlagsEnum = SymbolFlagsRegularEnum | SymbolFlagsConstEnum
|
||||||
|
SymbolFlagsVariable = SymbolFlagsFunctionScopedVariable | SymbolFlagsBlockScopedVariable
|
||||||
|
SymbolFlagsValue = SymbolFlagsVariable | SymbolFlagsProperty | SymbolFlagsEnumMember | SymbolFlagsObjectLiteral | SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsValueModule | SymbolFlagsMethod | SymbolFlagsGetAccessor | SymbolFlagsSetAccessor
|
||||||
|
SymbolFlagsType = SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsEnum | SymbolFlagsEnumMember | SymbolFlagsTypeLiteral | SymbolFlagsTypeParameter | SymbolFlagsTypeAlias
|
||||||
|
SymbolFlagsNamespace = SymbolFlagsValueModule | SymbolFlagsNamespaceModule | SymbolFlagsEnum
|
||||||
|
SymbolFlagsModule = SymbolFlagsValueModule | SymbolFlagsNamespaceModule
|
||||||
|
SymbolFlagsAccessor = SymbolFlagsGetAccessor | SymbolFlagsSetAccessor
|
||||||
|
|
||||||
|
// Variables can be redeclared, but can not redeclare a block-scoped declaration with the
|
||||||
|
// same name, or any other value that is not a variable, e.g. ValueModule or Class
|
||||||
|
SymbolFlagsFunctionScopedVariableExcludes = SymbolFlagsValue & ^SymbolFlagsFunctionScopedVariable
|
||||||
|
|
||||||
|
// Block-scoped declarations are not allowed to be re-declared
|
||||||
|
// they can not merge with anything in the value space
|
||||||
|
SymbolFlagsBlockScopedVariableExcludes = SymbolFlagsValue
|
||||||
|
|
||||||
|
SymbolFlagsParameterExcludes = SymbolFlagsValue
|
||||||
|
SymbolFlagsPropertyExcludes = SymbolFlagsValue & ^(SymbolFlagsProperty | SymbolFlagsAccessor)
|
||||||
|
SymbolFlagsEnumMemberExcludes = SymbolFlagsValue | SymbolFlagsType
|
||||||
|
SymbolFlagsFunctionExcludes = SymbolFlagsValue & ^(SymbolFlagsFunction | SymbolFlagsValueModule | SymbolFlagsClass)
|
||||||
|
SymbolFlagsClassExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^(SymbolFlagsValueModule | SymbolFlagsInterface | SymbolFlagsFunction) // class-interface mergability done in checker.ts
|
||||||
|
SymbolFlagsInterfaceExcludes = SymbolFlagsType & ^(SymbolFlagsInterface | SymbolFlagsClass)
|
||||||
|
SymbolFlagsRegularEnumExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^(SymbolFlagsRegularEnum | SymbolFlagsValueModule) // regular enums merge only with regular enums and modules
|
||||||
|
SymbolFlagsConstEnumExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^SymbolFlagsConstEnum // const enums merge only with const enums
|
||||||
|
SymbolFlagsValueModuleExcludes = SymbolFlagsValue & ^(SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsRegularEnum | SymbolFlagsValueModule)
|
||||||
|
SymbolFlagsNamespaceModuleExcludes = SymbolFlagsNone
|
||||||
|
SymbolFlagsMethodExcludes = SymbolFlagsValue & ^SymbolFlagsMethod
|
||||||
|
SymbolFlagsGetAccessorExcludes = SymbolFlagsValue & ^(SymbolFlagsSetAccessor | SymbolFlagsProperty)
|
||||||
|
SymbolFlagsSetAccessorExcludes = SymbolFlagsValue & ^(SymbolFlagsGetAccessor | SymbolFlagsProperty)
|
||||||
|
SymbolFlagsAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsProperty
|
||||||
|
SymbolFlagsTypeParameterExcludes = SymbolFlagsType & ^SymbolFlagsTypeParameter
|
||||||
|
SymbolFlagsTypeAliasExcludes = SymbolFlagsType
|
||||||
|
SymbolFlagsAliasExcludes = SymbolFlagsAlias
|
||||||
|
SymbolFlagsModuleMember = SymbolFlagsVariable | SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsEnum | SymbolFlagsModule | SymbolFlagsTypeAlias | SymbolFlagsAlias
|
||||||
|
SymbolFlagsExportHasLocal = SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsValueModule
|
||||||
|
SymbolFlagsBlockScoped = SymbolFlagsBlockScopedVariable | SymbolFlagsClass | SymbolFlagsEnum
|
||||||
|
SymbolFlagsPropertyOrAccessor = SymbolFlagsProperty | SymbolFlagsAccessor
|
||||||
|
SymbolFlagsClassMember = SymbolFlagsMethod | SymbolFlagsAccessor | SymbolFlagsProperty
|
||||||
|
SymbolFlagsExportSupportsDefaultModifier = SymbolFlagsClass | SymbolFlagsFunction | SymbolFlagsInterface
|
||||||
|
SymbolFlagsExportDoesNotSupportDefaultModifier = ^SymbolFlagsExportSupportsDefaultModifier
|
||||||
|
// The set of things we consider semantically classifiable. Used to speed up the LS during
|
||||||
|
// classification.
|
||||||
|
SymbolFlagsClassifiable = SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsTypeAlias | SymbolFlagsInterface | SymbolFlagsTypeParameter | SymbolFlagsModule | SymbolFlagsAlias
|
||||||
|
SymbolFlagsLateBindingContainer = SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsTypeLiteral | SymbolFlagsObjectLiteral | SymbolFlagsFunction
|
||||||
|
)
|
||||||
33
tools/tsgo/internal/ast/tokenflags.go
Normal file
33
tools/tsgo/internal/ast/tokenflags.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type TokenFlags int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenFlagsNone TokenFlags = 0
|
||||||
|
TokenFlagsPrecedingLineBreak TokenFlags = 1 << 0
|
||||||
|
TokenFlagsPrecedingJSDocComment TokenFlags = 1 << 1
|
||||||
|
TokenFlagsUnterminated TokenFlags = 1 << 2
|
||||||
|
TokenFlagsExtendedUnicodeEscape TokenFlags = 1 << 3 // e.g. `\u{10ffff}`
|
||||||
|
TokenFlagsScientific TokenFlags = 1 << 4 // e.g. `10e2`
|
||||||
|
TokenFlagsOctal TokenFlags = 1 << 5 // e.g. `0777`
|
||||||
|
TokenFlagsHexSpecifier TokenFlags = 1 << 6 // e.g. `0x00000000`
|
||||||
|
TokenFlagsBinarySpecifier TokenFlags = 1 << 7 // e.g. `0b0110010000000000`
|
||||||
|
TokenFlagsOctalSpecifier TokenFlags = 1 << 8 // e.g. `0o777`
|
||||||
|
TokenFlagsContainsSeparator TokenFlags = 1 << 9 // e.g. `0b1100_0101`
|
||||||
|
TokenFlagsUnicodeEscape TokenFlags = 1 << 10 // e.g. `\u00a0`
|
||||||
|
TokenFlagsContainsInvalidEscape TokenFlags = 1 << 11 // e.g. `\uhello`
|
||||||
|
TokenFlagsHexEscape TokenFlags = 1 << 12 // e.g. `\xa0`
|
||||||
|
TokenFlagsContainsLeadingZero TokenFlags = 1 << 13 // e.g. `0888`
|
||||||
|
TokenFlagsContainsInvalidSeparator TokenFlags = 1 << 14 // e.g. `0_1`
|
||||||
|
TokenFlagsPrecedingJSDocLeadingAsterisks TokenFlags = 1 << 15
|
||||||
|
TokenFlagsSingleQuote TokenFlags = 1 << 16 // e.g. `'abc'`
|
||||||
|
TokenFlagsPrecedingJSDocWithDeprecated TokenFlags = 1 << 17 // Preceding JSDoc comment contains @deprecated
|
||||||
|
TokenFlagsPrecedingJSDocWithSeeOrLink TokenFlags = 1 << 18 // Preceding JSDoc comment contains @see or @link
|
||||||
|
TokenFlagsBinaryOrOctalSpecifier TokenFlags = TokenFlagsBinarySpecifier | TokenFlagsOctalSpecifier
|
||||||
|
TokenFlagsWithSpecifier TokenFlags = TokenFlagsHexSpecifier | TokenFlagsBinaryOrOctalSpecifier
|
||||||
|
TokenFlagsStringLiteralFlags TokenFlags = TokenFlagsUnterminated | TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape | TokenFlagsSingleQuote
|
||||||
|
TokenFlagsNumericLiteralFlags TokenFlags = TokenFlagsScientific | TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsWithSpecifier | TokenFlagsContainsSeparator | TokenFlagsContainsInvalidSeparator
|
||||||
|
TokenFlagsTemplateLiteralLikeFlags TokenFlags = TokenFlagsUnterminated | TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape
|
||||||
|
TokenFlagsRegularExpressionLiteralFlags TokenFlags = TokenFlagsUnterminated
|
||||||
|
TokenFlagsIsInvalid TokenFlags = TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsContainsInvalidSeparator | TokenFlagsContainsInvalidEscape
|
||||||
|
)
|
||||||
4565
tools/tsgo/internal/ast/utilities.go
Normal file
4565
tools/tsgo/internal/ast/utilities.go
Normal file
File diff suppressed because it is too large
Load Diff
278
tools/tsgo/internal/ast/visitor.go
Normal file
278
tools/tsgo/internal/ast/visitor.go
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeVisitor
|
||||||
|
|
||||||
|
type NodeVisitor struct {
|
||||||
|
Visit func(node *Node) *Node // Required. The callback used to visit a node
|
||||||
|
Factory *NodeFactory // Required. The NodeFactory used to produce new nodes when passed to VisitEachChild
|
||||||
|
Hooks NodeVisitorHooks // Hooks to be invoked when visiting a node
|
||||||
|
}
|
||||||
|
|
||||||
|
// These hooks are used to intercept the default behavior of the visitor
|
||||||
|
type NodeVisitorHooks struct {
|
||||||
|
VisitNode func(node *Node, v *NodeVisitor) *Node // Overrides visiting a Node. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitToken func(node *TokenNode, v *NodeVisitor) *Node // Overrides visiting a TokenNode. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitNodes func(nodes *NodeList, v *NodeVisitor) *NodeList // Overrides visiting a NodeList. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitModifiers func(nodes *ModifierList, v *NodeVisitor) *ModifierList // Overrides visiting a ModifierList. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitEmbeddedStatement func(node *Statement, v *NodeVisitor) *Statement // Overrides visiting a Node when it is the embedded statement body of an iteration statement, `if` statement, or `with` statement. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitIterationBody func(node *Statement, v *NodeVisitor) *Statement // Overrides visiting a Node when it is the embedded statement body of an iteration statement. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitParameters func(nodes *ParameterList, v *NodeVisitor) *ParameterList // Overrides visiting a ParameterList. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitFunctionBody func(node *BlockOrExpression, v *NodeVisitor) *BlockOrExpression // Overrides visiting a function body. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
VisitTopLevelStatements func(nodes *StatementList, v *NodeVisitor) *StatementList // Overrides visiting a variable environment. Only invoked by the VisitEachChild method on a given Node subtype.
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNodeVisitor(visit func(node *Node) *Node, factory *NodeFactory, hooks NodeVisitorHooks) *NodeVisitor {
|
||||||
|
if factory == nil {
|
||||||
|
factory = &NodeFactory{}
|
||||||
|
}
|
||||||
|
return &NodeVisitor{Visit: visit, Factory: factory, Hooks: hooks}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) VisitSourceFile(node *SourceFile) *SourceFile {
|
||||||
|
return v.VisitNode(node.AsNode()).AsSourceFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visits a Node, possibly returning a new Node in its place.
|
||||||
|
//
|
||||||
|
// - If the input node is nil, then the output is nil.
|
||||||
|
// - If v.Visit is nil, then the output is the input.
|
||||||
|
// - If v.Visit returns nil, then the output is nil.
|
||||||
|
// - If v.Visit returns a SyntaxList Node, then the output is the only child of the SyntaxList Node.
|
||||||
|
func (v *NodeVisitor) VisitNode(node *Node) *Node {
|
||||||
|
if node == nil || v.Visit == nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Visit != nil {
|
||||||
|
visited := v.Visit(node)
|
||||||
|
if visited != nil && visited.Kind == KindSyntaxList {
|
||||||
|
nodes := visited.AsSyntaxList().Children
|
||||||
|
if len(nodes) != 1 {
|
||||||
|
panic("Expected only a single node to be written to output")
|
||||||
|
}
|
||||||
|
visited = nodes[0]
|
||||||
|
if visited != nil && visited.Kind == KindSyntaxList {
|
||||||
|
panic("The result of visiting and lifting a Node may not be SyntaxList")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visited
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visits an embedded Statement (i.e., the single statement body of a loop, `if..else` branch, etc.), possibly returning a new Statement in its place.
|
||||||
|
//
|
||||||
|
// - If the input node is nil, then the output is nil.
|
||||||
|
// - If v.Visit is nil, then the output is the input.
|
||||||
|
// - If v.Visit returns nil, then the output is nil.
|
||||||
|
// - If v.Visit returns a SyntaxList Node, then the output is either the only child of the SyntaxList Node, or a Block containing the nodes in the list.
|
||||||
|
func (v *NodeVisitor) VisitEmbeddedStatement(node *Statement) *Statement {
|
||||||
|
if node == nil || v.Visit == nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
visited := v.Visit(node)
|
||||||
|
if visited == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.liftToBlock(visited)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visits a NodeList, possibly returning a new NodeList in its place.
|
||||||
|
//
|
||||||
|
// - If the input NodeList is nil, the output is nil.
|
||||||
|
// - If v.Visit is nil, then the output is the input.
|
||||||
|
// - If v.Visit returns nil, the visited Node will be absent in the output.
|
||||||
|
// - If v.Visit returns a different Node than the input, a new NodeList will be generated and returned.
|
||||||
|
// - If v.Visit returns a SyntaxList Node, then the children of that node will be merged into the output and a new NodeList will be returned.
|
||||||
|
// - If this method returns a new NodeList for any reason, it will have the same Loc as the input NodeList.
|
||||||
|
func (v *NodeVisitor) VisitNodes(nodes *NodeList) *NodeList {
|
||||||
|
if nodes == nil || v.Visit == nil {
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
if result, changed := v.VisitSlice(nodes.Nodes); changed {
|
||||||
|
list := v.Factory.NewNodeList(result)
|
||||||
|
list.Loc = nodes.Loc
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visits a ModifierList, possibly returning a new ModifierList in its place.
|
||||||
|
//
|
||||||
|
// - If the input ModifierList is nil, the output is nil.
|
||||||
|
// - If v.Visit is nil, then the output is the input.
|
||||||
|
// - If v.Visit returns nil, the visited Node will be absent in the output.
|
||||||
|
// - If v.Visit returns a different Node than the input, a new ModifierList will be generated and returned.
|
||||||
|
// - If v.Visit returns a SyntaxList Node, then the children of that node will be merged into the output and a new NodeList will be returned.
|
||||||
|
// - If this method returns a new NodeList for any reason, it will have the same Loc as the input NodeList.
|
||||||
|
func (v *NodeVisitor) VisitModifiers(nodes *ModifierList) *ModifierList {
|
||||||
|
if nodes == nil || v.Visit == nil {
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
if result, changed := v.VisitSlice(nodes.Nodes); changed {
|
||||||
|
list := v.Factory.NewModifierList(result)
|
||||||
|
list.Loc = nodes.Loc
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visits a slice of Nodes, returning the resulting slice and a value indicating whether the slice was changed.
|
||||||
|
//
|
||||||
|
// - If the input slice is nil, the output is nil.
|
||||||
|
// - If v.Visit is nil, then the output is the input.
|
||||||
|
// - If v.Visit returns nil, the visited Node will be absent in the output.
|
||||||
|
// - If v.Visit returns a different Node than the input, a new slice will be generated and returned.
|
||||||
|
// - If v.Visit returns a SyntaxList Node, then the children of that node will be merged into the output and a new slice will be returned.
|
||||||
|
func (v *NodeVisitor) VisitSlice(nodes []*Node) (result []*Node, changed bool) {
|
||||||
|
if nodes == nil || v.Visit == nil {
|
||||||
|
return nodes, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(nodes); i++ {
|
||||||
|
node := nodes[i]
|
||||||
|
if v.Visit == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
visited := v.Visit(node)
|
||||||
|
if visited == nil || visited != node {
|
||||||
|
updated := slices.Clone(nodes[:i])
|
||||||
|
|
||||||
|
for {
|
||||||
|
// finish prior loop
|
||||||
|
switch {
|
||||||
|
case visited == nil: // do nothing
|
||||||
|
case visited.Kind == KindSyntaxList:
|
||||||
|
updated = append(updated, visited.AsSyntaxList().Children...)
|
||||||
|
default:
|
||||||
|
updated = append(updated, visited)
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
|
||||||
|
// loop over remaining elements
|
||||||
|
if i >= len(nodes) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Visit != nil {
|
||||||
|
node = nodes[i]
|
||||||
|
visited = v.Visit(node)
|
||||||
|
} else {
|
||||||
|
updated = append(updated, nodes[i:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visits each child of a Node, possibly returning a new Node of the same kind in its place.
|
||||||
|
func (v *NodeVisitor) VisitEachChild(node *Node) *Node {
|
||||||
|
if node == nil || v.Visit == nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.VisitEachChild(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitNode(node *Node) *Node {
|
||||||
|
if v.Hooks.VisitNode != nil {
|
||||||
|
return v.Hooks.VisitNode(node, v)
|
||||||
|
}
|
||||||
|
return v.VisitNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitEmbeddedStatement(node *Node) *Node {
|
||||||
|
if v.Hooks.VisitEmbeddedStatement != nil {
|
||||||
|
return v.Hooks.VisitEmbeddedStatement(node, v)
|
||||||
|
}
|
||||||
|
if v.Hooks.VisitNode != nil {
|
||||||
|
return v.liftToBlock(v.Hooks.VisitNode(node, v))
|
||||||
|
}
|
||||||
|
return v.VisitEmbeddedStatement(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitIterationBody(node *Statement) *Statement {
|
||||||
|
if v.Hooks.VisitIterationBody != nil {
|
||||||
|
return v.Hooks.VisitIterationBody(node, v)
|
||||||
|
}
|
||||||
|
return v.visitEmbeddedStatement(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitFunctionBody(node *BlockOrExpression) *BlockOrExpression {
|
||||||
|
if v.Hooks.VisitFunctionBody != nil {
|
||||||
|
return v.Hooks.VisitFunctionBody(node, v)
|
||||||
|
}
|
||||||
|
return v.visitNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitToken(node *Node) *Node {
|
||||||
|
if v.Hooks.VisitToken != nil {
|
||||||
|
return v.Hooks.VisitToken(node, v)
|
||||||
|
}
|
||||||
|
return v.VisitNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitNodes(nodes *NodeList) *NodeList {
|
||||||
|
if v.Hooks.VisitNodes != nil {
|
||||||
|
return v.Hooks.VisitNodes(nodes, v)
|
||||||
|
}
|
||||||
|
return v.VisitNodes(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitModifiers(nodes *ModifierList) *ModifierList {
|
||||||
|
if v.Hooks.VisitModifiers != nil {
|
||||||
|
return v.Hooks.VisitModifiers(nodes, v)
|
||||||
|
}
|
||||||
|
return v.VisitModifiers(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitParameters(nodes *ParameterList) *ParameterList {
|
||||||
|
if v.Hooks.VisitParameters != nil {
|
||||||
|
return v.Hooks.VisitParameters(nodes, v)
|
||||||
|
}
|
||||||
|
return v.visitNodes(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) visitTopLevelStatements(nodes *StatementList) *StatementList {
|
||||||
|
if v.Hooks.VisitTopLevelStatements != nil {
|
||||||
|
return v.Hooks.VisitTopLevelStatements(nodes, v)
|
||||||
|
}
|
||||||
|
return v.visitNodes(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *NodeVisitor) liftToBlock(node *Statement) *Statement {
|
||||||
|
var nodes []*Node
|
||||||
|
if node != nil {
|
||||||
|
if node.Kind == KindSyntaxList {
|
||||||
|
nodes = node.AsSyntaxList().Children
|
||||||
|
} else {
|
||||||
|
nodes = []*Node{node}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(nodes) == 1 {
|
||||||
|
node = nodes[0]
|
||||||
|
} else {
|
||||||
|
node = v.Factory.NewBlock(v.Factory.NewNodeList(nodes), true /*multiLine*/)
|
||||||
|
}
|
||||||
|
if node.Kind == KindSyntaxList {
|
||||||
|
panic("The result of visiting and lifting a Node may not be SyntaxList")
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
14
tools/tsgo/internal/astnav/testmain_test.go
Normal file
14
tools/tsgo/internal/astnav/testmain_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package astnav_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/baseline"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
core.ApplyDebugStackLimit()
|
||||||
|
defer baseline.Track()()
|
||||||
|
m.Run()
|
||||||
|
}
|
||||||
783
tools/tsgo/internal/astnav/tokens.go
Normal file
783
tools/tsgo/internal/astnav/tokens.go
Normal file
@@ -0,0 +1,783 @@
|
|||||||
|
package astnav
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/scanner"
|
||||||
|
)
|
||||||
|
|
||||||
|
func shouldRescanLessThanLessThanToken(s *scanner.Scanner, containingNode *ast.Node, token ast.Kind) bool {
|
||||||
|
return token == ast.KindLessThanLessThanToken && ast.IsJsxChild(containingNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanNavigationToken(s *scanner.Scanner, containingNode *ast.Node) ast.Kind {
|
||||||
|
token := s.Token()
|
||||||
|
if shouldRescanLessThanLessThanToken(s, containingNode, token) {
|
||||||
|
return s.ReScanJsxToken(true /*allowMultilineJsxText*/)
|
||||||
|
}
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTouchingPropertyName(sourceFile *ast.SourceFile, position int) *ast.Node {
|
||||||
|
return getTokenAtPosition(sourceFile, position, false /*allowPositionInLeadingTrivia*/, func(node *ast.Node) bool {
|
||||||
|
return ast.IsPropertyNameLiteral(node) || ast.IsKeywordKind(node.Kind) || ast.IsPrivateIdentifier(node)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTouchingToken(sourceFile *ast.SourceFile, position int) *ast.Node {
|
||||||
|
return getTokenAtPosition(sourceFile, position, false /*allowPositionInLeadingTrivia*/, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTokenAtPosition(sourceFile *ast.SourceFile, position int) *ast.Node {
|
||||||
|
return getTokenAtPosition(sourceFile, position, true /*allowPositionInLeadingTrivia*/, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTokenAtPosition(
|
||||||
|
sourceFile *ast.SourceFile,
|
||||||
|
position int,
|
||||||
|
allowPositionInLeadingTrivia bool,
|
||||||
|
includePrecedingTokenAtEndPosition func(node *ast.Node) bool,
|
||||||
|
) *ast.Node {
|
||||||
|
// getTokenAtPosition returns a token at the given position in the source file.
|
||||||
|
// The token can be a real node in the AST, or a synthesized token constructed
|
||||||
|
// with information from the scanner. Synthesized tokens are only created when
|
||||||
|
// needed, and they are stored in the source file's token cache such that multiple
|
||||||
|
// calls to getTokenAtPosition with the same position will return the same object
|
||||||
|
// in memory. If there is no token at the given position (possible when
|
||||||
|
// `allowPositionInLeadingTrivia` is false), the lowest node that encloses the
|
||||||
|
// position is returned.
|
||||||
|
|
||||||
|
// `next` tracks the node whose children will be visited on the next iteration.
|
||||||
|
// `prevSubtree` is a node whose end position is equal to the target position,
|
||||||
|
// only if `includePrecedingTokenAtEndPosition` is provided. Once set, the next
|
||||||
|
// iteration of the loop will test the rightmost token of `prevSubtree` to see
|
||||||
|
// if it should be returned.
|
||||||
|
var next, prevSubtree *ast.Node
|
||||||
|
current := sourceFile.AsNode()
|
||||||
|
// `left` tracks the lower boundary of the node/token that could be returned,
|
||||||
|
// and is eventually the scanner's start position, if the scanner is used.
|
||||||
|
left := 0
|
||||||
|
// `nodeAfterLeft` tracks the first node we visit after visiting the node that advances `left`.
|
||||||
|
// When scanning in between nodes for token, we should only scan up to the start of `nodeAfterLeft`.
|
||||||
|
var nodeAfterLeft *ast.Node
|
||||||
|
|
||||||
|
testNode := func(node *ast.Node) int {
|
||||||
|
if node.Kind != ast.KindEndOfFile && node.End() == position &&
|
||||||
|
includePrecedingTokenAtEndPosition != nil && node.Flags&ast.NodeFlagsReparsed == 0 {
|
||||||
|
prevSubtree = node
|
||||||
|
}
|
||||||
|
|
||||||
|
// A node "contains" the position if position < end, except nodes at the file end
|
||||||
|
// treat end as inclusive (there's nowhere else to look). This applies to the EOF
|
||||||
|
// token itself, and to JSDoc nodes reaching EOF (e.g. unterminated JSDoc comments).
|
||||||
|
if node.End() < position || node.End() == position &&
|
||||||
|
node.Kind != ast.KindEndOfFile &&
|
||||||
|
(!ast.IsJSDocKind(node.Kind) || node.End() != sourceFile.EndOfFileToken.End()) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
nodePos := getPosition(node, sourceFile, allowPositionInLeadingTrivia)
|
||||||
|
if nodePos > position {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// We zero in on the node that contains the target position by visiting each
|
||||||
|
// child and JSDoc comment of the current node. Node children are walked in
|
||||||
|
// order, while node lists are binary searched.
|
||||||
|
visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node {
|
||||||
|
// We can't abort visiting children, so once a match is found, we set `next`
|
||||||
|
// and do nothing on subsequent visits.
|
||||||
|
if node == nil || node.Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if nodeAfterLeft == nil {
|
||||||
|
nodeAfterLeft = node
|
||||||
|
}
|
||||||
|
if next == nil {
|
||||||
|
result := testNode(node)
|
||||||
|
switch result {
|
||||||
|
case -1:
|
||||||
|
if !ast.IsJSDocKind(node.Kind) {
|
||||||
|
// We can't move the left boundary into or beyond JSDoc,
|
||||||
|
// because we may end up returning the token after this JSDoc,
|
||||||
|
// constructing it with the scanner, and we need to include
|
||||||
|
// all its leading trivia in its position.
|
||||||
|
left = node.End()
|
||||||
|
}
|
||||||
|
nodeAfterLeft = nil
|
||||||
|
case 0:
|
||||||
|
next = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
visitNodeList := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if nodeList == nil || len(nodeList.Nodes) == 0 {
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
if nodeAfterLeft == nil {
|
||||||
|
for _, node := range nodeList.Nodes {
|
||||||
|
if node.Flags&ast.NodeFlagsReparsed == 0 {
|
||||||
|
nodeAfterLeft = node
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if next == nil {
|
||||||
|
if nodeList.End() == position && includePrecedingTokenAtEndPosition != nil {
|
||||||
|
left = nodeList.End()
|
||||||
|
nodeAfterLeft = nil
|
||||||
|
for i := len(nodeList.Nodes) - 1; i >= 0; i-- {
|
||||||
|
if nodeList.Nodes[i].Flags&ast.NodeFlagsReparsed == 0 {
|
||||||
|
prevSubtree = nodeList.Nodes[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if nodeList.End() <= position {
|
||||||
|
left = nodeList.End()
|
||||||
|
nodeAfterLeft = nil
|
||||||
|
} else if nodeList.Pos() <= position {
|
||||||
|
nodes := nodeList.Nodes
|
||||||
|
index, match := core.BinarySearchUniqueFunc(nodes, func(middle int, node *ast.Node) int {
|
||||||
|
if node.Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
cmp := testNode(node)
|
||||||
|
if cmp < 0 {
|
||||||
|
left = node.End()
|
||||||
|
nodeAfterLeft = nil
|
||||||
|
for i := middle + 1; i < len(nodes); i++ {
|
||||||
|
if nodes[i].Flags&ast.NodeFlagsReparsed == 0 {
|
||||||
|
nodeAfterLeft = nodes[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmp
|
||||||
|
})
|
||||||
|
if match && nodes[index].Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
// filter and search again
|
||||||
|
nodes = core.Filter(nodes, func(node *ast.Node) bool {
|
||||||
|
return node.Flags&ast.NodeFlagsReparsed == 0
|
||||||
|
})
|
||||||
|
index, match = core.BinarySearchUniqueFunc(nodes, func(middle int, node *ast.Node) int {
|
||||||
|
cmp := testNode(node)
|
||||||
|
if cmp < 0 {
|
||||||
|
left = node.End()
|
||||||
|
if middle+1 < len(nodes) {
|
||||||
|
nodeAfterLeft = nodes[middle+1]
|
||||||
|
} else {
|
||||||
|
nodeAfterLeft = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmp
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if match {
|
||||||
|
next = nodes[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
VisitEachChildAndJSDoc(current, sourceFile, visitNode, visitNodeList)
|
||||||
|
// If prevSubtree was set on the last iteration, it ends at the target position.
|
||||||
|
// Check if the rightmost token of prevSubtree should be returned based on the
|
||||||
|
// `includePrecedingTokenAtEndPosition` callback.
|
||||||
|
if prevSubtree != nil {
|
||||||
|
child := FindPrecedingTokenEx(sourceFile, position, prevSubtree, false /*excludeJSDoc*/)
|
||||||
|
if child != nil && child.End() == position && includePrecedingTokenAtEndPosition(child) {
|
||||||
|
// Optimization: includePrecedingTokenAtEndPosition only ever returns true
|
||||||
|
// for real AST nodes, so we don't run the scanner here.
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
prevSubtree = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No node was found that contains the target position, so we've gone as deep as
|
||||||
|
// we can in the AST. We've either found a token, or we need to run the scanner
|
||||||
|
// to construct one that isn't stored in the AST.
|
||||||
|
if next == nil {
|
||||||
|
if ast.IsTokenKind(current.Kind) || shouldSkipChild(current) {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
scanner := scanner.GetScannerForSourceFile(sourceFile, left)
|
||||||
|
end := current.End()
|
||||||
|
// We should only scan up to the start of the next node in the AST after the node ending at position `left`.
|
||||||
|
// It is necessary to enforce this invariant in cases where `position` occurs in between two node/tokens,
|
||||||
|
// such that we would not find a token in the loop below before we reach the next node.
|
||||||
|
// We can fall into this case when `allowPositionInLeadingTrivia` is false and `position` is in a leading trivia,
|
||||||
|
// or when `position` would be in the leading trivia of a node but this node is inside JSDoc:
|
||||||
|
// ```
|
||||||
|
// /**
|
||||||
|
// * @type {{
|
||||||
|
// */*$*/ identifier: boolean;
|
||||||
|
// * }}
|
||||||
|
// */
|
||||||
|
// ```
|
||||||
|
// The position of marker '$' falls in between the asterisk token and the identifier token, but is not
|
||||||
|
// part of the leading trivia for `identifier`.
|
||||||
|
if nodeAfterLeft != nil {
|
||||||
|
end = nodeAfterLeft.Pos()
|
||||||
|
}
|
||||||
|
for left < end {
|
||||||
|
token := scanNavigationToken(scanner, current)
|
||||||
|
tokenFullStart := scanner.TokenFullStart()
|
||||||
|
tokenStart := core.IfElse(allowPositionInLeadingTrivia, tokenFullStart, scanner.TokenStart())
|
||||||
|
tokenEnd := scanner.TokenEnd()
|
||||||
|
flags := scanner.TokenFlags()
|
||||||
|
if tokenEnd > end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if tokenStart <= position && (position < tokenEnd) {
|
||||||
|
if token == ast.KindIdentifier || !ast.IsTokenKind(token) {
|
||||||
|
if ast.IsJSDocKind(current.Kind) {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("did not expect %s to have %s in its trivia", current.Kind.String(), token.String()))
|
||||||
|
}
|
||||||
|
return sourceFile.GetOrCreateToken(token, tokenFullStart, tokenEnd, current, flags)
|
||||||
|
}
|
||||||
|
if includePrecedingTokenAtEndPosition != nil && tokenEnd == position {
|
||||||
|
prevToken := sourceFile.GetOrCreateToken(token, tokenFullStart, tokenEnd, current, flags)
|
||||||
|
if includePrecedingTokenAtEndPosition(prevToken) {
|
||||||
|
return prevToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
left = tokenEnd
|
||||||
|
scanner.Scan()
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
current = next
|
||||||
|
left = current.Pos()
|
||||||
|
nodeAfterLeft = nil
|
||||||
|
next = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPosition(node *ast.Node, sourceFile *ast.SourceFile, allowPositionInLeadingTrivia bool) int {
|
||||||
|
if allowPositionInLeadingTrivia {
|
||||||
|
return node.Pos()
|
||||||
|
}
|
||||||
|
return scanner.GetTokenPosOfNode(node, sourceFile, true /*includeJSDoc*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findRightmostNode(node *ast.Node) *ast.Node {
|
||||||
|
var next *ast.Node
|
||||||
|
current := node
|
||||||
|
visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node {
|
||||||
|
if node != nil {
|
||||||
|
next = node
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
visitNodes := func(nodeList *ast.NodeList, visitor *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if nodeList != nil {
|
||||||
|
if rightmost := ast.FindLastVisibleNode(nodeList.Nodes); rightmost != nil {
|
||||||
|
next = rightmost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
visitor := getNodeVisitor(visitNode, visitNodes)
|
||||||
|
|
||||||
|
for {
|
||||||
|
current.VisitEachChild(visitor)
|
||||||
|
if next == nil {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
current = next
|
||||||
|
next = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func VisitEachChildAndJSDoc(
|
||||||
|
node *ast.Node,
|
||||||
|
sourceFile *ast.SourceFile,
|
||||||
|
visitNode func(*ast.Node, *ast.NodeVisitor) *ast.Node,
|
||||||
|
visitNodes func(*ast.NodeList, *ast.NodeVisitor) *ast.NodeList,
|
||||||
|
) {
|
||||||
|
visitor := getNodeVisitor(visitNode, visitNodes)
|
||||||
|
for _, jsdoc := range node.JSDoc(sourceFile) {
|
||||||
|
if visitor.Hooks.VisitNode != nil {
|
||||||
|
visitor.Hooks.VisitNode(jsdoc, visitor)
|
||||||
|
} else {
|
||||||
|
visitor.VisitNode(jsdoc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.VisitEachChild(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
comparisonLessThan = -1
|
||||||
|
comparisonEqualTo = 0
|
||||||
|
comparisonGreaterThan = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Finds the leftmost token satisfying `position < token.End()`.
|
||||||
|
// If the leftmost token satisfying `position < token.End()` is invalid, or if position
|
||||||
|
// is in the trivia of that leftmost token,
|
||||||
|
// we will find the rightmost valid token with `token.End() <= position`.
|
||||||
|
func FindPrecedingToken(sourceFile *ast.SourceFile, position int) *ast.Node {
|
||||||
|
return FindPrecedingTokenEx(sourceFile, position, nil, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindPrecedingTokenEx(sourceFile *ast.SourceFile, position int, startNode *ast.Node, excludeJSDoc bool) *ast.Node {
|
||||||
|
var find func(node *ast.Node) *ast.Node
|
||||||
|
find = func(n *ast.Node) *ast.Node {
|
||||||
|
if ast.IsNonWhitespaceToken(n) && n.Kind != ast.KindEndOfFile {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// `foundChild` is the leftmost node that contains the target position.
|
||||||
|
// `prevChild` is the last visited child of the current node.
|
||||||
|
var foundChild, prevChild *ast.Node
|
||||||
|
visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node {
|
||||||
|
// skip synthesized nodes (that will exist now because of jsdoc handling)
|
||||||
|
if node == nil || node.Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
if foundChild != nil { // We cannot abort visiting children, so once the desired child is found, we do nothing.
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
if position < node.End() && (prevChild == nil || prevChild.End() <= position) {
|
||||||
|
foundChild = node
|
||||||
|
} else {
|
||||||
|
prevChild = node
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
visitNodes := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if foundChild != nil {
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
if nodeList != nil && len(nodeList.Nodes) > 0 {
|
||||||
|
nodes := nodeList.Nodes
|
||||||
|
index, match := core.BinarySearchUniqueFunc(nodes, func(middle int, _ *ast.Node) int {
|
||||||
|
// synthetic jsdoc nodes should have jsdocNode.End() <= n.Pos()
|
||||||
|
if nodes[middle].Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return comparisonLessThan
|
||||||
|
}
|
||||||
|
if position < nodes[middle].End() {
|
||||||
|
if middle == 0 || position >= nodes[middle-1].End() {
|
||||||
|
return comparisonEqualTo
|
||||||
|
}
|
||||||
|
return comparisonGreaterThan
|
||||||
|
}
|
||||||
|
return comparisonLessThan
|
||||||
|
})
|
||||||
|
|
||||||
|
if match {
|
||||||
|
foundChild = nodes[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
validLookupIndex := core.IfElse(match, index-1, len(nodes)-1)
|
||||||
|
for i := validLookupIndex; i >= 0; i-- {
|
||||||
|
if nodes[i].Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if prevChild == nil {
|
||||||
|
prevChild = nodes[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
VisitEachChildAndJSDoc(n, sourceFile, visitNode, visitNodes)
|
||||||
|
|
||||||
|
if foundChild != nil {
|
||||||
|
// Note that the span of a node's tokens is [getStartOfNode(node, ...), node.end).
|
||||||
|
// Given that `position < child.end` and child has constituent tokens, we distinguish these cases:
|
||||||
|
// 1) `position` precedes `child`'s tokens or `child` has no tokens (ie: in a comment or whitespace preceding `child`):
|
||||||
|
// we need to find the last token in a previous child node or child tokens.
|
||||||
|
// 2) `position` is within the same span: we recurse on `child`.
|
||||||
|
start := GetStartOfNode(foundChild, sourceFile, !excludeJSDoc /*includeJSDoc*/)
|
||||||
|
lookInPreviousChild := start >= position || // cursor in the leading trivia or preceding tokens
|
||||||
|
!isValidPrecedingNode(foundChild, sourceFile)
|
||||||
|
if lookInPreviousChild {
|
||||||
|
if position >= foundChild.Pos() {
|
||||||
|
// Find jsdoc preceding the foundChild.
|
||||||
|
var jsDoc *ast.Node
|
||||||
|
nodeJSDoc := n.JSDoc(sourceFile)
|
||||||
|
for i := len(nodeJSDoc) - 1; i >= 0; i-- {
|
||||||
|
if nodeJSDoc[i].Pos() >= foundChild.Pos() {
|
||||||
|
jsDoc = nodeJSDoc[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if jsDoc != nil {
|
||||||
|
if !excludeJSDoc && position < jsDoc.End() {
|
||||||
|
return find(jsDoc)
|
||||||
|
} else {
|
||||||
|
return findRightmostValidToken(jsDoc.End(), sourceFile, n, position, excludeJSDoc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return findRightmostValidToken(foundChild.Pos(), sourceFile, n, -1 /*position*/, excludeJSDoc)
|
||||||
|
} else { // Answer is in tokens between two visited children.
|
||||||
|
return findRightmostValidToken(foundChild.Pos(), sourceFile, n, position, excludeJSDoc)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// position is in [foundChild.getStart(), foundChild.End): recur.
|
||||||
|
return find(foundChild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have two cases here: either the position is at the end of the file,
|
||||||
|
// or the desired token is in the unvisited trailing tokens of the current node.
|
||||||
|
if position >= n.End() {
|
||||||
|
return findRightmostValidToken(n.End(), sourceFile, n, -1 /*position*/, excludeJSDoc)
|
||||||
|
} else {
|
||||||
|
return findRightmostValidToken(n.End(), sourceFile, n, position, excludeJSDoc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var node *ast.Node
|
||||||
|
if startNode != nil {
|
||||||
|
node = startNode
|
||||||
|
} else {
|
||||||
|
node = sourceFile.AsNode()
|
||||||
|
}
|
||||||
|
result := find(node)
|
||||||
|
if result != nil && ast.IsWhitespaceOnlyJsxText(result) {
|
||||||
|
panic("Expected result to be a non-whitespace token.")
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidPrecedingNode(node *ast.Node, sourceFile *ast.SourceFile) bool {
|
||||||
|
if node.Kind == ast.KindEndOfFile {
|
||||||
|
return len(node.JSDoc(sourceFile)) > 0
|
||||||
|
}
|
||||||
|
start := GetStartOfNode(node, sourceFile, false /*includeJSDoc*/)
|
||||||
|
width := node.End() - start
|
||||||
|
return !(ast.IsWhitespaceOnlyJsxText(node) || width == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStartOfNode(node *ast.Node, file *ast.SourceFile, includeJSDoc bool) int {
|
||||||
|
return scanner.GetTokenPosOfNode(node, file, includeJSDoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks for rightmost valid token in the range [startPos, endPos).
|
||||||
|
// If position is >= 0, looks for rightmost valid token that precedes or touches that position.
|
||||||
|
func findRightmostValidToken(endPos int, sourceFile *ast.SourceFile, containingNode *ast.Node, position int, excludeJSDoc bool) *ast.Node {
|
||||||
|
if position == -1 {
|
||||||
|
position = containingNode.End()
|
||||||
|
}
|
||||||
|
var find func(n *ast.Node, endPos int) *ast.Node
|
||||||
|
find = func(n *ast.Node, endPos int) *ast.Node {
|
||||||
|
if n == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ast.IsNonWhitespaceToken(n) {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
var rightmostValidNode *ast.Node
|
||||||
|
rightmostVisitedNodes := make([]*ast.Node, 0, 1) // Nodes after the last valid node.
|
||||||
|
hasChildren := false
|
||||||
|
shouldVisitNode := func(node *ast.Node) bool {
|
||||||
|
// Node is synthetic or out of the desired range: don't visit it.
|
||||||
|
return !(node.Flags&ast.NodeFlagsReparsed != 0 ||
|
||||||
|
node.End() > endPos || GetStartOfNode(node, sourceFile, !excludeJSDoc /*includeJSDoc*/) >= position)
|
||||||
|
}
|
||||||
|
visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node {
|
||||||
|
if node == nil || node.Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
hasChildren = true
|
||||||
|
if !shouldVisitNode(node) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
rightmostVisitedNodes = append(rightmostVisitedNodes, node)
|
||||||
|
if isValidPrecedingNode(node, sourceFile) {
|
||||||
|
rightmostValidNode = node
|
||||||
|
rightmostVisitedNodes = rightmostVisitedNodes[:0]
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
visitNodes := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if nodeList != nil && len(nodeList.Nodes) > 0 {
|
||||||
|
hasChildren = true
|
||||||
|
index, _ := core.BinarySearchUniqueFunc(nodeList.Nodes, func(middle int, node *ast.Node) int {
|
||||||
|
if node.End() > endPos {
|
||||||
|
return comparisonGreaterThan
|
||||||
|
}
|
||||||
|
return comparisonLessThan
|
||||||
|
})
|
||||||
|
validIndex := -1
|
||||||
|
for i := index - 1; i >= 0; i-- {
|
||||||
|
if !shouldVisitNode(nodeList.Nodes[i]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if isValidPrecedingNode(nodeList.Nodes[i], sourceFile) {
|
||||||
|
validIndex = i
|
||||||
|
rightmostValidNode = nodeList.Nodes[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := validIndex + 1; i < index; i++ {
|
||||||
|
if !shouldVisitNode(nodeList.Nodes[i]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rightmostVisitedNodes = append(rightmostVisitedNodes, nodeList.Nodes[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
VisitEachChildAndJSDoc(n, sourceFile, visitNode, visitNodes)
|
||||||
|
|
||||||
|
// Three cases:
|
||||||
|
// 1. The answer is a token of `rightmostValidNode`.
|
||||||
|
// 2. The answer is one of the unvisited tokens that occur after the rightmost valid node.
|
||||||
|
// 3. The current node is a childless, token-less node. The answer is the current node.
|
||||||
|
|
||||||
|
// Case 2: Look at unvisited trailing tokens that occur in between the rightmost visited nodes.
|
||||||
|
if !shouldSkipChild(n) { // JSDoc nodes don't include trivia tokens as children.
|
||||||
|
var startPos int
|
||||||
|
if rightmostValidNode != nil {
|
||||||
|
startPos = rightmostValidNode.End()
|
||||||
|
} else {
|
||||||
|
startPos = n.Pos()
|
||||||
|
}
|
||||||
|
scanner := scanner.GetScannerForSourceFile(sourceFile, startPos)
|
||||||
|
var tokens []*ast.Node
|
||||||
|
for _, visitedNode := range rightmostVisitedNodes {
|
||||||
|
// Trailing tokens that occur before this node.
|
||||||
|
for startPos < min(visitedNode.Pos(), position) {
|
||||||
|
token := scanNavigationToken(scanner, n)
|
||||||
|
tokenStart := scanner.TokenStart()
|
||||||
|
if tokenStart >= position {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tokenFullStart := scanner.TokenFullStart()
|
||||||
|
tokenEnd := scanner.TokenEnd()
|
||||||
|
startPos = tokenEnd
|
||||||
|
flags := scanner.TokenFlags()
|
||||||
|
tokens = append(tokens, sourceFile.GetOrCreateToken(token, tokenFullStart, tokenEnd, n, flags))
|
||||||
|
scanner.Scan()
|
||||||
|
}
|
||||||
|
startPos = visitedNode.End()
|
||||||
|
scanner.ResetPos(startPos)
|
||||||
|
scanner.Scan()
|
||||||
|
}
|
||||||
|
// Trailing tokens after last visited node.
|
||||||
|
for startPos < min(endPos, position) {
|
||||||
|
token := scanNavigationToken(scanner, n)
|
||||||
|
tokenStart := scanner.TokenStart()
|
||||||
|
if tokenStart >= position {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tokenFullStart := scanner.TokenFullStart()
|
||||||
|
tokenEnd := scanner.TokenEnd()
|
||||||
|
startPos = tokenEnd
|
||||||
|
flags := scanner.TokenFlags()
|
||||||
|
tokens = append(tokens, sourceFile.GetOrCreateToken(token, tokenFullStart, tokenEnd, n, flags))
|
||||||
|
scanner.Scan()
|
||||||
|
}
|
||||||
|
|
||||||
|
lastToken := len(tokens) - 1
|
||||||
|
// Find preceding valid token.
|
||||||
|
for i := lastToken; i >= 0; i-- {
|
||||||
|
if !ast.IsWhitespaceOnlyJsxText(tokens[i]) {
|
||||||
|
return tokens[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 3: childless node.
|
||||||
|
if !hasChildren {
|
||||||
|
if n != containingNode {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Case 1: recur on rightmostValidNode.
|
||||||
|
if rightmostValidNode != nil {
|
||||||
|
endPos = rightmostValidNode.End()
|
||||||
|
}
|
||||||
|
return find(rightmostValidNode, endPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
return find(containingNode, endPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindNextToken(previousToken *ast.Node, parent *ast.Node, file *ast.SourceFile) *ast.Node {
|
||||||
|
var find func(n *ast.Node) *ast.Node
|
||||||
|
find = func(n *ast.Node) *ast.Node {
|
||||||
|
if ast.IsTokenKind(n.Kind) && n.Pos() == previousToken.End() {
|
||||||
|
// this is token that starts at the end of previous token - return it
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
// Node that contains `previousToken` or occurs immediately after it.
|
||||||
|
var foundNode *ast.Node
|
||||||
|
visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node {
|
||||||
|
if node != nil && node.Flags&ast.NodeFlagsReparsed == 0 &&
|
||||||
|
node.Pos() <= previousToken.End() && node.End() > previousToken.End() {
|
||||||
|
foundNode = node
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
visitNodes := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if nodeList != nil && len(nodeList.Nodes) > 0 && foundNode == nil {
|
||||||
|
nodes := nodeList.Nodes
|
||||||
|
index, match := core.BinarySearchUniqueFunc(nodes, func(_ int, node *ast.Node) int {
|
||||||
|
if node.Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return comparisonLessThan
|
||||||
|
}
|
||||||
|
if node.Pos() > previousToken.End() {
|
||||||
|
return comparisonGreaterThan
|
||||||
|
}
|
||||||
|
if node.End() <= previousToken.Pos() {
|
||||||
|
return comparisonLessThan
|
||||||
|
}
|
||||||
|
return comparisonEqualTo
|
||||||
|
})
|
||||||
|
if match {
|
||||||
|
foundNode = nodes[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
VisitEachChildAndJSDoc(n, file, visitNode, visitNodes)
|
||||||
|
// Cases:
|
||||||
|
// 1. no answer exists
|
||||||
|
// 2. answer is an unvisited token
|
||||||
|
// 3. answer is in the visited found node
|
||||||
|
|
||||||
|
// Case 3: look for the next token inside the found node.
|
||||||
|
if foundNode != nil {
|
||||||
|
return find(foundNode)
|
||||||
|
}
|
||||||
|
startPos := previousToken.End()
|
||||||
|
// Case 2: look for the next token directly.
|
||||||
|
if startPos >= n.Pos() && startPos < n.End() {
|
||||||
|
scanner := scanner.GetScannerForSourceFile(file, startPos)
|
||||||
|
token := scanner.Token()
|
||||||
|
tokenFullStart := scanner.TokenFullStart()
|
||||||
|
tokenEnd := scanner.TokenEnd()
|
||||||
|
flags := scanner.TokenFlags()
|
||||||
|
// Use tokenFullStart (which includes leading trivia) to match TS's
|
||||||
|
// findNextToken behavior where `n.pos === previousToken.end` is checked
|
||||||
|
// (TS's pos includes trivia, same as Go's Pos()/tokenFullStart).
|
||||||
|
if tokenFullStart == previousToken.End() {
|
||||||
|
return file.GetOrCreateToken(token, tokenFullStart, tokenEnd, n, flags)
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("Expected to find next token at %d, got token %s at %d", previousToken.End(), token, tokenFullStart))
|
||||||
|
}
|
||||||
|
// Case 3: no answer.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return find(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNodeVisitor(
|
||||||
|
visitNode func(*ast.Node, *ast.NodeVisitor) *ast.Node,
|
||||||
|
visitNodes func(*ast.NodeList, *ast.NodeVisitor) *ast.NodeList,
|
||||||
|
) *ast.NodeVisitor {
|
||||||
|
var wrappedVisitNode func(*ast.Node, *ast.NodeVisitor) *ast.Node
|
||||||
|
var wrappedVisitNodes func(*ast.NodeList, *ast.NodeVisitor) *ast.NodeList
|
||||||
|
if visitNode != nil {
|
||||||
|
wrappedVisitNode = func(n *ast.Node, v *ast.NodeVisitor) *ast.Node {
|
||||||
|
if ast.IsJSDocSingleCommentNodeComment(n) {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
return visitNode(n, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if visitNodes != nil {
|
||||||
|
wrappedVisitNodes = func(n *ast.NodeList, v *ast.NodeVisitor) *ast.NodeList {
|
||||||
|
if ast.IsJSDocSingleCommentNodeList(n) {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
return visitNodes(n, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast.NewNodeVisitor(core.Identity, nil, ast.NodeVisitorHooks{
|
||||||
|
VisitNode: wrappedVisitNode,
|
||||||
|
VisitToken: wrappedVisitNode,
|
||||||
|
VisitNodes: wrappedVisitNodes,
|
||||||
|
VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList {
|
||||||
|
if modifiers != nil {
|
||||||
|
wrappedVisitNodes(&modifiers.NodeList, visitor)
|
||||||
|
}
|
||||||
|
return modifiers
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldSkipChild(node *ast.Node) bool {
|
||||||
|
return node.Kind == ast.KindJSDoc ||
|
||||||
|
node.Kind == ast.KindJSDocText ||
|
||||||
|
node.Kind == ast.KindJSDocTypeLiteral ||
|
||||||
|
node.Kind == ast.KindJSDocSignature ||
|
||||||
|
ast.IsJSDocLinkLike(node) ||
|
||||||
|
ast.IsJSDocTag(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindChildOfKind searches for a child node or token of the specified kind within a containing node.
|
||||||
|
// This function scans through both AST nodes and intervening tokens to find the first match.
|
||||||
|
func FindChildOfKind(containingNode *ast.Node, kind ast.Kind, sourceFile *ast.SourceFile) *ast.Node {
|
||||||
|
lastNodePos := containingNode.Pos()
|
||||||
|
scan := scanner.GetScannerForSourceFile(sourceFile, lastNodePos)
|
||||||
|
|
||||||
|
var foundChild *ast.Node
|
||||||
|
visitNode := func(node *ast.Node) bool {
|
||||||
|
if node == nil || node.Flags&ast.NodeFlagsReparsed != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Look for child in preceding tokens.
|
||||||
|
startPos := lastNodePos
|
||||||
|
for startPos < node.Pos() {
|
||||||
|
tokenKind := scan.Token()
|
||||||
|
tokenEnd := scan.TokenEnd()
|
||||||
|
if tokenKind == kind {
|
||||||
|
tokenFullStart := scan.TokenFullStart()
|
||||||
|
flags := scan.TokenFlags()
|
||||||
|
foundChild = sourceFile.GetOrCreateToken(tokenKind, tokenFullStart, tokenEnd, containingNode, flags)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
startPos = tokenEnd
|
||||||
|
scan.Scan()
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.Kind == kind {
|
||||||
|
foundChild = node
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
lastNodePos = node.End()
|
||||||
|
scan.ResetPos(lastNodePos)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.ForEachChildAndJSDoc(containingNode, sourceFile, visitNode)
|
||||||
|
|
||||||
|
if foundChild != nil {
|
||||||
|
return foundChild
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for child in trailing tokens.
|
||||||
|
startPos := lastNodePos
|
||||||
|
for startPos < containingNode.End() {
|
||||||
|
tokenKind := scan.Token()
|
||||||
|
tokenEnd := scan.TokenEnd()
|
||||||
|
if tokenKind == kind {
|
||||||
|
tokenFullStart := scan.TokenFullStart()
|
||||||
|
flags := scan.TokenFlags()
|
||||||
|
token := sourceFile.GetOrCreateToken(tokenKind, tokenFullStart, tokenEnd, containingNode, flags)
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
startPos = tokenEnd
|
||||||
|
scan.Scan()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
626
tools/tsgo/internal/astnav/tokens_test.go
Normal file
626
tools/tsgo/internal/astnav/tokens_test.go
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
package astnav_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/astnav"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/parser"
|
||||||
|
"github.com/microsoft/typescript-go/internal/repo"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/baseline"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/jstest"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testFiles = []string{
|
||||||
|
filepath.Join(repo.TypeScriptSubmodulePath(), "src/services/mapCode.ts"),
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTokenAtPosition(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(t)
|
||||||
|
jstest.SkipIfNoNodeJS(t)
|
||||||
|
|
||||||
|
t.Run("baseline", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
baselineTokens(
|
||||||
|
t,
|
||||||
|
"GetTokenAtPosition",
|
||||||
|
false, /*includeEOF*/
|
||||||
|
func(fileText string, positions []int) []*tokenInfo {
|
||||||
|
return tsGetTokensAtPositions(t, fileText, positions)
|
||||||
|
},
|
||||||
|
func(file *ast.SourceFile, pos int) *tokenInfo {
|
||||||
|
return toTokenInfo(astnav.GetTokenAtPosition(file, pos))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("go baseline json", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
baselineGoTokensJSON(t, "GetTokenAtPosition", func(file *ast.SourceFile, pos int) *tokenInfo {
|
||||||
|
return toTokenInfo(astnav.GetTokenAtPosition(file, pos))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("JSDoc type assertion", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
fileText := `function foo(x) {
|
||||||
|
const s = /**@type {string}*/(x)
|
||||||
|
}`
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/test.js",
|
||||||
|
Path: "/test.js",
|
||||||
|
}, fileText, core.ScriptKindJS)
|
||||||
|
|
||||||
|
// Position of 'x' inside the parenthesized expression (position 52)
|
||||||
|
position := 52
|
||||||
|
|
||||||
|
// This should not panic - it previously panicked with:
|
||||||
|
// "did not expect KindParenthesizedExpression to have KindIdentifier in its trivia"
|
||||||
|
token := astnav.GetTouchingPropertyName(file, position)
|
||||||
|
if token == nil {
|
||||||
|
t.Fatal("Expected to get a token, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The function may return either the identifier itself or the containing
|
||||||
|
// parenthesized expression, depending on how the AST is structured
|
||||||
|
if token.Kind != ast.KindIdentifier && token.Kind != ast.KindParenthesizedExpression {
|
||||||
|
t.Errorf("Expected identifier or parenthesized expression, got %s", token.Kind)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("JSDoc type assertion with comment", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Exact code from the issue report
|
||||||
|
fileText := `function foo(x) {
|
||||||
|
const s = /**@type {string}*/(x) // Go-to-definition on x causes panic
|
||||||
|
}`
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/test.js",
|
||||||
|
Path: "/test.js",
|
||||||
|
}, fileText, core.ScriptKindJS)
|
||||||
|
|
||||||
|
// Find position of 'x' in the type assertion
|
||||||
|
xPos := 52 // Position of 'x' in (x)
|
||||||
|
|
||||||
|
// This should not panic
|
||||||
|
token := astnav.GetTouchingPropertyName(file, xPos)
|
||||||
|
assert.Assert(t, token != nil, "Expected to get a token")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("pointer equality", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
fileText := `
|
||||||
|
function foo() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/file.ts",
|
||||||
|
Path: "/file.ts",
|
||||||
|
}, fileText, core.ScriptKindTS)
|
||||||
|
assert.Equal(t, astnav.GetTokenAtPosition(file, 0), astnav.GetTokenAtPosition(file, 0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTouchingPropertyName(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
jstest.SkipIfNoNodeJS(t)
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(t)
|
||||||
|
|
||||||
|
baselineTokens(
|
||||||
|
t,
|
||||||
|
"GetTouchingPropertyName",
|
||||||
|
false, /*includeEOF*/
|
||||||
|
func(fileText string, positions []int) []*tokenInfo {
|
||||||
|
return tsGetTouchingPropertyName(t, fileText, positions)
|
||||||
|
},
|
||||||
|
func(file *ast.SourceFile, pos int) *tokenInfo {
|
||||||
|
return toTokenInfo(astnav.GetTouchingPropertyName(file, pos))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run("go baseline json", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
baselineGoTokensJSON(t, "GetTouchingPropertyName", func(file *ast.SourceFile, pos int) *tokenInfo {
|
||||||
|
return toTokenInfo(astnav.GetTouchingPropertyName(file, pos))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func baselineTokens(t *testing.T, testName string, includeEOF bool, getTSTokens func(fileText string, positions []int) []*tokenInfo, getGoToken func(file *ast.SourceFile, pos int) *tokenInfo) {
|
||||||
|
for _, fileName := range testFiles {
|
||||||
|
t.Run(filepath.Base(fileName), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
fileText, err := os.ReadFile(fileName)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
positions := make([]int, len(fileText)+core.IfElse(includeEOF, 1, 0))
|
||||||
|
for i := range positions {
|
||||||
|
positions[i] = i
|
||||||
|
}
|
||||||
|
tsTokens := getTSTokens(string(fileText), positions)
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/file.ts",
|
||||||
|
Path: "/file.ts",
|
||||||
|
}, string(fileText), core.ScriptKindTS)
|
||||||
|
|
||||||
|
var output strings.Builder
|
||||||
|
currentRange := core.NewTextRange(0, 0)
|
||||||
|
currentDiff := tokenDiff{}
|
||||||
|
|
||||||
|
for pos, tsToken := range tsTokens {
|
||||||
|
goToken := getGoToken(file, pos)
|
||||||
|
diff := tokenDiff{goToken: goToken, tsToken: tsToken}
|
||||||
|
|
||||||
|
if !diffEqual(currentDiff, diff) {
|
||||||
|
if !tokensEqual(currentDiff.goToken, currentDiff.tsToken) {
|
||||||
|
writeRangeDiff(&output, file, currentDiff, currentRange, pos)
|
||||||
|
}
|
||||||
|
currentDiff = diff
|
||||||
|
currentRange = core.NewTextRange(pos, pos)
|
||||||
|
}
|
||||||
|
currentRange = currentRange.WithEnd(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tokensEqual(currentDiff.goToken, currentDiff.tsToken) {
|
||||||
|
writeRangeDiff(&output, file, currentDiff, currentRange, len(tsTokens)-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseline.Run(
|
||||||
|
t,
|
||||||
|
fmt.Sprintf("%s.%s.baseline.txt", testName, filepath.Base(fileName)),
|
||||||
|
core.IfElse(output.Len() > 0, output.String(), baseline.NoContent),
|
||||||
|
baseline.Options{
|
||||||
|
Subfolder: "astnav",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenRun struct {
|
||||||
|
StartPos int `json:"startPos"`
|
||||||
|
EndPos int `json:"endPos"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
NodePos int `json:"nodePos"`
|
||||||
|
NodeEnd int `json:"nodeEnd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func baselineGoTokensJSON(t *testing.T, testName string, getGoToken func(file *ast.SourceFile, pos int) *tokenInfo) {
|
||||||
|
for _, fileName := range testFiles {
|
||||||
|
t.Run(filepath.Base(fileName), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
fileText, err := os.ReadFile(fileName)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/file.ts",
|
||||||
|
Path: "/file.ts",
|
||||||
|
}, string(fileText), core.ScriptKindTS)
|
||||||
|
|
||||||
|
maxPos := len(fileText)
|
||||||
|
var runs []tokenRun
|
||||||
|
var current *tokenRun
|
||||||
|
|
||||||
|
for pos := range maxPos {
|
||||||
|
token := getGoToken(file, pos)
|
||||||
|
if current != nil && token != nil && current.Kind == token.Kind && current.NodePos == token.Pos && current.NodeEnd == token.End {
|
||||||
|
current.EndPos = pos
|
||||||
|
} else {
|
||||||
|
if current != nil {
|
||||||
|
runs = append(runs, *current)
|
||||||
|
}
|
||||||
|
if token != nil {
|
||||||
|
current = &tokenRun{
|
||||||
|
StartPos: pos,
|
||||||
|
EndPos: pos,
|
||||||
|
Kind: token.Kind,
|
||||||
|
NodePos: token.Pos,
|
||||||
|
NodeEnd: token.End,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if current != nil {
|
||||||
|
runs = append(runs, *current)
|
||||||
|
}
|
||||||
|
|
||||||
|
output := core.Must(core.StringifyJson(runs, "", " "))
|
||||||
|
|
||||||
|
baseline.Run(
|
||||||
|
t,
|
||||||
|
fmt.Sprintf("%s.%s.baseline.json", testName, filepath.Base(fileName)),
|
||||||
|
output,
|
||||||
|
baseline.Options{
|
||||||
|
Subfolder: "astnav",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenDiff struct {
|
||||||
|
goToken *tokenInfo
|
||||||
|
tsToken *tokenInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenInfo struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Pos int `json:"pos"`
|
||||||
|
End int `json:"end"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toTokenInfo(node *ast.Node) *tokenInfo {
|
||||||
|
if node == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
kind := strings.Replace(node.Kind.String(), "Kind", "", 1)
|
||||||
|
switch kind {
|
||||||
|
case "EndOfFile":
|
||||||
|
kind = "EndOfFileToken"
|
||||||
|
}
|
||||||
|
return &tokenInfo{
|
||||||
|
Kind: kind,
|
||||||
|
Pos: node.Pos(),
|
||||||
|
End: node.End(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func diffEqual(a, b tokenDiff) bool {
|
||||||
|
return tokensEqual(a.goToken, b.goToken) && tokensEqual(a.tsToken, b.tsToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokensEqual(t1, t2 *tokenInfo) bool {
|
||||||
|
if t1 == nil || t2 == nil {
|
||||||
|
return t1 == t2
|
||||||
|
}
|
||||||
|
return *t1 == *t2
|
||||||
|
}
|
||||||
|
|
||||||
|
func tsGetTokensAtPositions(t testing.TB, fileText string, positions []int) []*tokenInfo {
|
||||||
|
dir := t.TempDir()
|
||||||
|
err := os.WriteFile(filepath.Join(dir, "file.ts"), []byte(fileText), 0o644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
err = os.WriteFile(filepath.Join(dir, "positions.json"), []byte(core.Must(core.StringifyJson(positions, "", ""))), 0o644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
script := `
|
||||||
|
import fs from "fs";
|
||||||
|
export default (ts) => {
|
||||||
|
const positions = JSON.parse(fs.readFileSync("positions.json", "utf8"));
|
||||||
|
const fileText = fs.readFileSync("file.ts", "utf8");
|
||||||
|
const file = ts.createSourceFile(
|
||||||
|
"file.ts",
|
||||||
|
fileText,
|
||||||
|
{ languageVersion: ts.ScriptTarget.Latest, jsDocParsingMode: ts.JSDocParsingMode.ParseAll },
|
||||||
|
/*setParentNodes*/ true
|
||||||
|
);
|
||||||
|
return positions.map(position => {
|
||||||
|
let token = ts.getTokenAtPosition(file, position);
|
||||||
|
if (token.kind === ts.SyntaxKind.SyntaxList) {
|
||||||
|
token = token.parent;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kind: ts.Debug.formatSyntaxKind(token.kind),
|
||||||
|
pos: token.pos,
|
||||||
|
end: token.end,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};`
|
||||||
|
|
||||||
|
info, err := jstest.EvalNodeScriptWithTS[[]*tokenInfo](t, script, dir, "")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
func tsGetTouchingPropertyName(t testing.TB, fileText string, positions []int) []*tokenInfo {
|
||||||
|
dir := t.TempDir()
|
||||||
|
err := os.WriteFile(filepath.Join(dir, "file.ts"), []byte(fileText), 0o644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
err = os.WriteFile(filepath.Join(dir, "positions.json"), []byte(core.Must(core.StringifyJson(positions, "", ""))), 0o644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
script := `
|
||||||
|
import fs from "fs";
|
||||||
|
export default (ts) => {
|
||||||
|
const positions = JSON.parse(fs.readFileSync("positions.json", "utf8"));
|
||||||
|
const fileText = fs.readFileSync("file.ts", "utf8");
|
||||||
|
const file = ts.createSourceFile(
|
||||||
|
"file.ts",
|
||||||
|
fileText,
|
||||||
|
{ languageVersion: ts.ScriptTarget.Latest, jsDocParsingMode: ts.JSDocParsingMode.ParseAll },
|
||||||
|
/*setParentNodes*/ true
|
||||||
|
);
|
||||||
|
return positions.map(position => {
|
||||||
|
let token = ts.getTouchingPropertyName(file, position);
|
||||||
|
if (token.kind === ts.SyntaxKind.SyntaxList) {
|
||||||
|
token = token.parent;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kind: ts.Debug.formatSyntaxKind(token.kind),
|
||||||
|
pos: token.pos,
|
||||||
|
end: token.end,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};`
|
||||||
|
|
||||||
|
info, err := jstest.EvalNodeScriptWithTS[[]*tokenInfo](t, script, dir, "")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeRangeDiff(output *strings.Builder, file *ast.SourceFile, diff tokenDiff, rng core.TextRange, position int) {
|
||||||
|
lines := file.ECMALineMap()
|
||||||
|
|
||||||
|
tsTokenPos := position
|
||||||
|
goTokenPos := position
|
||||||
|
tsTokenEnd := position
|
||||||
|
goTokenEnd := position
|
||||||
|
if diff.tsToken != nil {
|
||||||
|
tsTokenPos = diff.tsToken.Pos
|
||||||
|
tsTokenEnd = diff.tsToken.End
|
||||||
|
}
|
||||||
|
if diff.goToken != nil {
|
||||||
|
goTokenPos = diff.goToken.Pos
|
||||||
|
goTokenEnd = diff.goToken.End
|
||||||
|
}
|
||||||
|
tsStartLine, _ := core.PositionToLineAndByteOffset(tsTokenPos, lines)
|
||||||
|
tsEndLine, _ := core.PositionToLineAndByteOffset(tsTokenEnd, lines)
|
||||||
|
goStartLine, _ := core.PositionToLineAndByteOffset(goTokenPos, lines)
|
||||||
|
goEndLine, _ := core.PositionToLineAndByteOffset(goTokenEnd, lines)
|
||||||
|
|
||||||
|
contextLines := 2
|
||||||
|
startLine := min(tsStartLine, goStartLine)
|
||||||
|
endLine := max(tsEndLine, goEndLine)
|
||||||
|
markerLines := []int{tsStartLine, tsEndLine, goStartLine, goEndLine}
|
||||||
|
slices.Sort(markerLines)
|
||||||
|
contextStart := max(0, startLine-contextLines)
|
||||||
|
contextEnd := min(len(lines)-1, endLine+contextLines)
|
||||||
|
digits := len(strconv.Itoa(contextEnd))
|
||||||
|
|
||||||
|
shouldTruncate := func(line int) (result bool, skipTo int) {
|
||||||
|
index, _ := slices.BinarySearch(markerLines, line)
|
||||||
|
if index == 0 || index == len(markerLines) {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
low := markerLines[index-1]
|
||||||
|
high := markerLines[index]
|
||||||
|
if line-low > 5 && high-line > 5 {
|
||||||
|
return true, high - 5
|
||||||
|
}
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if output.Len() > 0 {
|
||||||
|
output.WriteString("\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
output.WriteString(fmt.Sprintf("〚Positions: [%d, %d]〛\n", rng.Pos(), rng.End()))
|
||||||
|
if diff.tsToken != nil {
|
||||||
|
output.WriteString(fmt.Sprintf("【TS: %s [%d, %d)】\n", diff.tsToken.Kind, tsTokenPos, tsTokenEnd))
|
||||||
|
} else {
|
||||||
|
output.WriteString("【TS: nil】\n")
|
||||||
|
}
|
||||||
|
if diff.goToken != nil {
|
||||||
|
output.WriteString(fmt.Sprintf("《Go: %s [%d, %d)》\n", diff.goToken.Kind, goTokenPos, goTokenEnd))
|
||||||
|
} else {
|
||||||
|
output.WriteString("《Go: nil》\n")
|
||||||
|
}
|
||||||
|
for line := contextStart; line <= contextEnd; line++ {
|
||||||
|
if truncate, skipTo := shouldTruncate(line); truncate {
|
||||||
|
output.WriteString(fmt.Sprintf("%s │........ %d lines omitted ........\n", strings.Repeat(" ", digits), skipTo-line+1))
|
||||||
|
line = skipTo
|
||||||
|
}
|
||||||
|
output.WriteString(fmt.Sprintf("%*d │", digits, line+1))
|
||||||
|
end := len(file.Text()) + 1
|
||||||
|
if line < len(lines)-1 {
|
||||||
|
end = int(lines[line+1])
|
||||||
|
}
|
||||||
|
for pos := int(lines[line]); pos < end; pos++ {
|
||||||
|
if pos == rng.End()+1 {
|
||||||
|
output.WriteString("〛")
|
||||||
|
}
|
||||||
|
if diff.tsToken != nil && pos == tsTokenEnd {
|
||||||
|
output.WriteString("】")
|
||||||
|
}
|
||||||
|
if diff.goToken != nil && pos == goTokenEnd {
|
||||||
|
output.WriteString("》")
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff.goToken != nil && pos == goTokenPos {
|
||||||
|
output.WriteString("《")
|
||||||
|
}
|
||||||
|
if diff.tsToken != nil && pos == tsTokenPos {
|
||||||
|
output.WriteString("【")
|
||||||
|
}
|
||||||
|
if pos == rng.Pos() {
|
||||||
|
output.WriteString("〚")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos < len(file.Text()) {
|
||||||
|
output.WriteByte(file.Text()[pos])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindPrecedingToken(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(t)
|
||||||
|
jstest.SkipIfNoNodeJS(t)
|
||||||
|
|
||||||
|
t.Run("baseline", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
baselineTokens(
|
||||||
|
t,
|
||||||
|
"FindPrecedingToken",
|
||||||
|
true, /*includeEOF*/
|
||||||
|
func(fileText string, positions []int) []*tokenInfo {
|
||||||
|
return tsFindPrecedingTokens(t, fileText, positions)
|
||||||
|
},
|
||||||
|
func(file *ast.SourceFile, pos int) *tokenInfo {
|
||||||
|
return toTokenInfo(astnav.FindPrecedingToken(file, pos))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("go baseline json", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
baselineGoTokensJSON(t, "FindPrecedingToken", func(file *ast.SourceFile, pos int) *tokenInfo {
|
||||||
|
return toTokenInfo(astnav.FindPrecedingToken(file, pos))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindNextToken(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
repo.SkipIfNoTypeScriptSubmodule(t)
|
||||||
|
|
||||||
|
t.Run("go baseline json", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
baselineGoTokensJSON(t, "FindNextToken", func(file *ast.SourceFile, pos int) (result *tokenInfo) {
|
||||||
|
// FindNextToken panics (like Go's assert) when the scanner finds trivia between
|
||||||
|
// previousToken.End() and the next syntactic token. Catch those to avoid crashing
|
||||||
|
// the baseline generator; those positions will be absent from the baseline.
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
result = nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
token := astnav.GetTokenAtPosition(file, pos)
|
||||||
|
next := astnav.FindNextToken(token, file.AsNode(), file)
|
||||||
|
return toTokenInfo(next)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnitFindPrecedingToken(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
fileContent string
|
||||||
|
position int
|
||||||
|
expectedKind ast.Kind
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "after dot in jsdoc",
|
||||||
|
fileContent: `import {
|
||||||
|
CharacterCodes,
|
||||||
|
compareStringsCaseInsensitive,
|
||||||
|
compareStringsCaseSensitive,
|
||||||
|
compareValues,
|
||||||
|
Comparison,
|
||||||
|
Debug,
|
||||||
|
endsWith,
|
||||||
|
equateStringsCaseInsensitive,
|
||||||
|
equateStringsCaseSensitive,
|
||||||
|
GetCanonicalFileName,
|
||||||
|
getDeclarationFileExtension,
|
||||||
|
getStringComparer,
|
||||||
|
identity,
|
||||||
|
lastOrUndefined,
|
||||||
|
Path,
|
||||||
|
some,
|
||||||
|
startsWith,
|
||||||
|
} from "./_namespaces/ts.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internally, we represent paths as strings with '/' as the directory separator.
|
||||||
|
* When we make system calls (eg: LanguageServiceHost.getDirectory()),
|
||||||
|
* we expect the host to correctly handle paths in our specified format.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export const directorySeparator = "/";
|
||||||
|
/** @internal */
|
||||||
|
export const altDirectorySeparator = "\\";
|
||||||
|
const urlSchemeSeparator = "://";
|
||||||
|
const backslashRegExp = /\\/g;
|
||||||
|
|
||||||
|
|
||||||
|
backslashRegExp.
|
||||||
|
|
||||||
|
//Path Tests
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a charCode corresponds to '/' or '\'.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function isAnyDirectorySeparator(charCode: number): boolean {
|
||||||
|
return charCode === CharacterCodes.slash || charCode === CharacterCodes.backslash;
|
||||||
|
}`,
|
||||||
|
position: 839,
|
||||||
|
expectedKind: ast.KindDotToken,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "after comma in parameter list",
|
||||||
|
fileContent: `takesCb((n, s, ))`,
|
||||||
|
position: 15,
|
||||||
|
expectedKind: ast.KindCommaToken,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
|
||||||
|
FileName: "/file.ts",
|
||||||
|
Path: "/file.ts",
|
||||||
|
}, testCase.fileContent, core.ScriptKindTS)
|
||||||
|
token := astnav.FindPrecedingToken(file, testCase.position)
|
||||||
|
assert.Equal(t, token.Kind, testCase.expectedKind)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tsFindPrecedingTokens(t *testing.T, fileText string, positions []int) []*tokenInfo {
|
||||||
|
dir := t.TempDir()
|
||||||
|
err := os.WriteFile(filepath.Join(dir, "file.ts"), []byte(fileText), 0o644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
err = os.WriteFile(filepath.Join(dir, "positions.json"), []byte(core.Must(core.StringifyJson(positions, "", ""))), 0o644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
script := `
|
||||||
|
import fs from "fs";
|
||||||
|
export default (ts) => {
|
||||||
|
const positions = JSON.parse(fs.readFileSync("positions.json", "utf8"));
|
||||||
|
const fileText = fs.readFileSync("file.ts", "utf8");
|
||||||
|
const file = ts.createSourceFile(
|
||||||
|
"file.ts",
|
||||||
|
fileText,
|
||||||
|
{ languageVersion: ts.ScriptTarget.Latest, jsDocParsingMode: ts.JSDocParsingMode.ParseAll },
|
||||||
|
/*setParentNodes*/ true
|
||||||
|
);
|
||||||
|
return positions.map(position => {
|
||||||
|
let token = ts.findPrecedingToken(position, file);
|
||||||
|
if (token === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (token.kind === ts.SyntaxKind.SyntaxList) {
|
||||||
|
token = token.parent;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kind: ts.Debug.formatSyntaxKind(token.kind),
|
||||||
|
pos: token.pos,
|
||||||
|
end: token.end,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};`
|
||||||
|
info, err := jstest.EvalNodeScriptWithTS[[]*tokenInfo](t, script, dir, "")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
return info
|
||||||
|
}
|
||||||
2795
tools/tsgo/internal/binder/binder.go
Normal file
2795
tools/tsgo/internal/binder/binder.go
Normal file
File diff suppressed because it is too large
Load Diff
46
tools/tsgo/internal/binder/binder_test.go
Normal file
46
tools/tsgo/internal/binder/binder_test.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package binder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/parser"
|
||||||
|
"github.com/microsoft/typescript-go/internal/testutil/fixtures"
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkBind(b *testing.B) {
|
||||||
|
for _, f := range fixtures.BenchFixtures {
|
||||||
|
b.Run(f.Name(), func(b *testing.B) {
|
||||||
|
f.SkipIfNotExist(b)
|
||||||
|
|
||||||
|
fileName := tspath.GetNormalizedAbsolutePath(f.Path(), "/")
|
||||||
|
path := tspath.ToPath(fileName, "/", osvfs.FS().UseCaseSensitiveFileNames())
|
||||||
|
sourceText := f.ReadFile(b)
|
||||||
|
|
||||||
|
parseOptions := ast.SourceFileParseOptions{
|
||||||
|
FileName: fileName,
|
||||||
|
Path: path,
|
||||||
|
}
|
||||||
|
scriptKind := core.GetScriptKindFromFileName(fileName)
|
||||||
|
|
||||||
|
sourceFiles := make([]*ast.SourceFile, b.N)
|
||||||
|
for i := range b.N {
|
||||||
|
sourceFiles[i] = parser.ParseSourceFile(parseOptions, sourceText, scriptKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The above parses do a lot of work; ensure GC is finished before we start collecting performance data.
|
||||||
|
// GC must be called twice to allow things to settle.
|
||||||
|
runtime.GC()
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := range b.N {
|
||||||
|
BindSourceFile(sourceFiles[i])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
498
tools/tsgo/internal/binder/nameresolver.go
Normal file
498
tools/tsgo/internal/binder/nameresolver.go
Normal file
@@ -0,0 +1,498 @@
|
|||||||
|
package binder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/diagnostics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NameResolver struct {
|
||||||
|
CompilerOptions *core.CompilerOptions
|
||||||
|
GetSymbolOfDeclaration func(node *ast.Node) *ast.Symbol
|
||||||
|
Error func(location *ast.Node, message *diagnostics.Message, args ...any) *ast.Diagnostic
|
||||||
|
Globals ast.SymbolTable
|
||||||
|
ArgumentsSymbol *ast.Symbol
|
||||||
|
RequireSymbol *ast.Symbol
|
||||||
|
Lookup func(symbols ast.SymbolTable, name string, meaning ast.SymbolFlags) *ast.Symbol
|
||||||
|
SymbolReferenced func(symbol *ast.Symbol, meaning ast.SymbolFlags)
|
||||||
|
SetRequiresScopeChangeCache func(node *ast.Node, value core.Tristate)
|
||||||
|
GetRequiresScopeChangeCache func(node *ast.Node) core.Tristate
|
||||||
|
OnPropertyWithInvalidInitializer func(location *ast.Node, name string, declaration *ast.Node, result *ast.Symbol) bool
|
||||||
|
OnFailedToResolveSymbol func(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message)
|
||||||
|
OnSuccessfullyResolvedSymbol func(location *ast.Node, result *ast.Symbol, meaning ast.SymbolFlags, lastLocation *ast.Node, associatedDeclarationForContainingInitializerOrBindingName *ast.Node, withinDeferredContext bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) Resolve(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *ast.Symbol {
|
||||||
|
var result *ast.Symbol
|
||||||
|
var lastLocation *ast.Node
|
||||||
|
var lastSelfReferenceLocation *ast.Node
|
||||||
|
var propertyWithInvalidInitializer *ast.Node
|
||||||
|
var associatedDeclarationForContainingInitializerOrBindingName *ast.Node
|
||||||
|
var withinDeferredContext bool
|
||||||
|
var grandparent *ast.Node
|
||||||
|
originalLocation := location // needed for did-you-mean error reporting, which gathers candidates starting from the original location
|
||||||
|
nameIsConst := name == "const"
|
||||||
|
loop:
|
||||||
|
for location != nil {
|
||||||
|
if nameIsConst && ast.IsConstAssertion(location) {
|
||||||
|
// `const` in an `as const` has no symbol, but issues no error because there is no *actual* lookup of the type
|
||||||
|
// (it refers to the constant type of the expression instead)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ast.IsModuleOrEnumDeclaration(location) && lastLocation != nil && location.Name() == lastLocation {
|
||||||
|
// If lastLocation is the name of a namespace or enum, skip the parent since it will have is own locals that could
|
||||||
|
// conflict.
|
||||||
|
lastLocation = location
|
||||||
|
location = location.Parent
|
||||||
|
}
|
||||||
|
locals := location.Locals()
|
||||||
|
// Locals of a source file are not in scope (because they get merged into the global symbol table)
|
||||||
|
if locals != nil && !ast.IsGlobalSourceFile(location) {
|
||||||
|
result = r.lookup(locals, name, meaning)
|
||||||
|
if result != nil {
|
||||||
|
useResult := true
|
||||||
|
if ast.IsFunctionLike(location) && lastLocation != nil && lastLocation != location.Body() {
|
||||||
|
// symbol lookup restrictions for function-like declarations
|
||||||
|
// - Type parameters of a function are in scope in the entire function declaration, including the parameter
|
||||||
|
// list and return type. However, local types are only in scope in the function body.
|
||||||
|
// - parameters are only in the scope of function body
|
||||||
|
// This restriction does not apply to JSDoc comment types because they are parented
|
||||||
|
// at a higher level than type parameters would normally be
|
||||||
|
if meaning&result.Flags&ast.SymbolFlagsType != 0 && lastLocation.Kind != ast.KindJSDoc {
|
||||||
|
// type parameters are visible in parameter list, return type and type parameter list.
|
||||||
|
// Synthetic fake scopes are added for signatures so type parameters are accessible from them.
|
||||||
|
useResult = result.Flags&ast.SymbolFlagsTypeParameter != 0 &&
|
||||||
|
(lastLocation.Flags&ast.NodeFlagsSynthesized != 0 ||
|
||||||
|
lastLocation == location.Type() ||
|
||||||
|
lastLocation.Kind == ast.KindParameter ||
|
||||||
|
lastLocation.Kind == ast.KindJSDocParameterTag ||
|
||||||
|
lastLocation.Kind == ast.KindJSDocReturnTag ||
|
||||||
|
lastLocation.Kind == ast.KindTypeParameter)
|
||||||
|
}
|
||||||
|
if meaning&result.Flags&ast.SymbolFlagsVariable != 0 {
|
||||||
|
// expression inside parameter will lookup as normal variable scope when targeting es2015+
|
||||||
|
if r.useOuterVariableScopeInParameter(result, location, lastLocation) {
|
||||||
|
useResult = false
|
||||||
|
} else if result.Flags&ast.SymbolFlagsFunctionScopedVariable != 0 {
|
||||||
|
// parameters are visible only inside function body, parameter list and return type
|
||||||
|
// technically for parameter list case here we might mix parameters and variables declared in function,
|
||||||
|
// however it is detected separately when checking initializers of parameters
|
||||||
|
// to make sure that they reference no variables declared after them.
|
||||||
|
useResult = lastLocation.Kind == ast.KindParameter ||
|
||||||
|
lastLocation.Flags&ast.NodeFlagsSynthesized != 0 ||
|
||||||
|
lastLocation == location.Type() && ast.FindAncestor(result.ValueDeclaration, ast.IsParameterDeclaration) != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if location.Kind == ast.KindConditionalType {
|
||||||
|
// A type parameter declared using 'infer T' in a conditional type is visible only in
|
||||||
|
// the true branch of the conditional type.
|
||||||
|
useResult = lastLocation == location.AsConditionalTypeNode().TrueType
|
||||||
|
}
|
||||||
|
if useResult {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
result = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation)
|
||||||
|
switch location.Kind {
|
||||||
|
case ast.KindSourceFile:
|
||||||
|
if !ast.IsExternalOrCommonJSModule(location.AsSourceFile()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case ast.KindModuleDeclaration:
|
||||||
|
moduleSymbol := r.getSymbolOfDeclaration(location)
|
||||||
|
if moduleSymbol == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
moduleExports := moduleSymbol.Exports
|
||||||
|
if ast.IsSourceFile(location) || (ast.IsModuleDeclaration(location) && location.Flags&ast.NodeFlagsAmbient != 0 && !ast.IsGlobalScopeAugmentation(location)) {
|
||||||
|
// It's an external module. First see if the module has an export default and if the local
|
||||||
|
// name of that export default matches.
|
||||||
|
result = moduleExports[ast.InternalSymbolNameDefault]
|
||||||
|
if result != nil {
|
||||||
|
localSymbol := GetLocalSymbolForExportDefault(result)
|
||||||
|
if localSymbol != nil && result.Flags&meaning != 0 && localSymbol.Name == name {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
result = nil
|
||||||
|
}
|
||||||
|
// Because of module/namespace merging, a module's exports are in scope,
|
||||||
|
// yet we never want to treat an export specifier as putting a member in scope.
|
||||||
|
// Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
|
||||||
|
// Two things to note about this:
|
||||||
|
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
|
||||||
|
// on an export specifier is that it might find the export specifier itself, and try to
|
||||||
|
// resolve it as an alias. This will cause the checker to consider the export specifier
|
||||||
|
// a circular alias reference when it might not be.
|
||||||
|
// 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely*
|
||||||
|
// an alias. If we used &, we'd be throwing out symbols that have non alias aspects,
|
||||||
|
// which is not the desired behavior.
|
||||||
|
moduleExport := moduleExports[name]
|
||||||
|
if moduleExport != nil && moduleExport.Flags == ast.SymbolFlagsAlias && (ast.GetDeclarationOfKind(moduleExport, ast.KindExportSpecifier) != nil || ast.GetDeclarationOfKind(moduleExport, ast.KindNamespaceExport) != nil) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name != ast.InternalSymbolNameDefault {
|
||||||
|
if result = r.lookup(moduleExports, name, meaning&ast.SymbolFlagsModuleMember); result != nil {
|
||||||
|
if ast.IsSourceFile(location) && location.AsSourceFile().CommonJSModuleIndicator != nil && result.Flags&ast.SymbolFlagsType == 0 {
|
||||||
|
result = nil
|
||||||
|
} else {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindEnumDeclaration:
|
||||||
|
enumSymbol := r.getSymbolOfDeclaration(location)
|
||||||
|
if enumSymbol == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result = r.lookup(enumSymbol.Exports, name, meaning&ast.SymbolFlagsEnumMember)
|
||||||
|
if result != nil {
|
||||||
|
if nameNotFoundMessage != nil && r.CompilerOptions.GetIsolatedModules() && location.Flags&ast.NodeFlagsAmbient == 0 && ast.GetSourceFileOfNode(location) != ast.GetSourceFileOfNode(result.ValueDeclaration) {
|
||||||
|
isolatedModulesLikeFlagName := core.IfElse(r.CompilerOptions.VerbatimModuleSyntax == core.TSTrue, "verbatimModuleSyntax", "isolatedModules")
|
||||||
|
r.error(originalLocation, diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead,
|
||||||
|
name, isolatedModulesLikeFlagName, enumSymbol.Name+"."+name)
|
||||||
|
}
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
case ast.KindPropertyDeclaration:
|
||||||
|
if !ast.IsStatic(location) {
|
||||||
|
ctor := ast.FindConstructorDeclaration(location.Parent)
|
||||||
|
if ctor != nil && ctor.Locals() != nil {
|
||||||
|
if r.lookup(ctor.Locals(), name, meaning&ast.SymbolFlagsValue) != nil {
|
||||||
|
// Remember the property node, it will be used later to report appropriate error
|
||||||
|
propertyWithInvalidInitializer = location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindInterfaceDeclaration:
|
||||||
|
result = r.lookup(r.getSymbolOfDeclaration(location).Members, name, meaning&ast.SymbolFlagsType)
|
||||||
|
if result != nil {
|
||||||
|
if !isTypeParameterSymbolDeclaredInContainer(result, location) {
|
||||||
|
// ignore type parameters not declared in this container
|
||||||
|
result = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if lastLocation != nil && ast.IsStatic(lastLocation) {
|
||||||
|
// TypeScript 1.0 spec (April 2014): 3.4.1
|
||||||
|
// The scope of a type parameter extends over the entire declaration with which the type
|
||||||
|
// parameter list is associated, with the exception of static member declarations in classes.
|
||||||
|
if nameNotFoundMessage != nil {
|
||||||
|
r.error(originalLocation, diagnostics.Static_members_cannot_reference_class_type_parameters)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
if ast.IsClassExpression(location) && meaning&ast.SymbolFlagsClass != 0 {
|
||||||
|
className := location.Name()
|
||||||
|
if className != nil && name == className.Text() {
|
||||||
|
result = location.Symbol()
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindExpressionWithTypeArguments:
|
||||||
|
if lastLocation == location.Expression() && ast.IsHeritageClause(location.Parent) && location.Parent.AsHeritageClause().Token == ast.KindExtendsKeyword {
|
||||||
|
container := location.Parent.Parent
|
||||||
|
if ast.IsClassLike(container) {
|
||||||
|
result = r.lookup(r.getSymbolOfDeclaration(container).Members, name, meaning&ast.SymbolFlagsType)
|
||||||
|
if result != nil {
|
||||||
|
if nameNotFoundMessage != nil {
|
||||||
|
r.error(originalLocation, diagnostics.Base_class_expressions_cannot_reference_class_type_parameters)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// It is not legal to reference a class's own type parameters from a computed property name that
|
||||||
|
// belongs to the class. For example:
|
||||||
|
//
|
||||||
|
// function foo<T>() { return '' }
|
||||||
|
// class C<T> { // <-- Class's own type parameter T
|
||||||
|
// [foo<T>()]() { } // <-- Reference to T from class's own computed property
|
||||||
|
// }
|
||||||
|
case ast.KindComputedPropertyName:
|
||||||
|
grandparent = location.Parent.Parent
|
||||||
|
if ast.IsClassLike(grandparent) || ast.IsInterfaceDeclaration(grandparent) {
|
||||||
|
// A reference to this grandparent's type parameters would be an error
|
||||||
|
result = r.lookup(r.getSymbolOfDeclaration(grandparent).Members, name, meaning&ast.SymbolFlagsType)
|
||||||
|
if result != nil {
|
||||||
|
if nameNotFoundMessage != nil {
|
||||||
|
r.error(originalLocation, diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindMethodDeclaration, ast.KindConstructor, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindFunctionDeclaration:
|
||||||
|
if meaning&ast.SymbolFlagsVariable != 0 && name == "arguments" {
|
||||||
|
result = r.argumentsSymbol()
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
case ast.KindFunctionExpression:
|
||||||
|
if meaning&ast.SymbolFlagsVariable != 0 && name == "arguments" {
|
||||||
|
result = r.argumentsSymbol()
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
if meaning&ast.SymbolFlagsFunction != 0 {
|
||||||
|
functionName := location.AsFunctionExpression().Name()
|
||||||
|
if functionName != nil && name == functionName.Text() {
|
||||||
|
result = location.Symbol()
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindDecorator:
|
||||||
|
// Decorators are resolved at the class declaration. Resolving at the parameter
|
||||||
|
// or member would result in looking up locals in the method.
|
||||||
|
//
|
||||||
|
// function y() {}
|
||||||
|
// class C {
|
||||||
|
// method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
if location.Parent != nil && location.Parent.Kind == ast.KindParameter {
|
||||||
|
location = location.Parent
|
||||||
|
}
|
||||||
|
// function y() {}
|
||||||
|
// class C {
|
||||||
|
// @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method.
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class Decorators are resolved outside of the class to avoid referencing type parameters of that class.
|
||||||
|
//
|
||||||
|
// type T = number;
|
||||||
|
// declare function y(x: T): any;
|
||||||
|
// @param(1 as T) // <-- T should resolve to the type alias outside of class C
|
||||||
|
// class C<T> {}
|
||||||
|
if location.Parent != nil && (ast.IsClassElement(location.Parent) || location.Parent.Kind == ast.KindClassDeclaration) {
|
||||||
|
location = location.Parent
|
||||||
|
}
|
||||||
|
case ast.KindParameter:
|
||||||
|
parameterDeclaration := location.AsParameterDeclaration()
|
||||||
|
if lastLocation != nil && (lastLocation == parameterDeclaration.Initializer ||
|
||||||
|
lastLocation == parameterDeclaration.Name() && ast.IsBindingPattern(lastLocation)) {
|
||||||
|
if associatedDeclarationForContainingInitializerOrBindingName == nil {
|
||||||
|
associatedDeclarationForContainingInitializerOrBindingName = location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindBindingElement:
|
||||||
|
bindingElement := location.AsBindingElement()
|
||||||
|
if lastLocation != nil && (lastLocation == bindingElement.Initializer ||
|
||||||
|
lastLocation == bindingElement.Name() && ast.IsBindingPattern(lastLocation)) {
|
||||||
|
if ast.IsPartOfParameterDeclaration(location) && associatedDeclarationForContainingInitializerOrBindingName == nil {
|
||||||
|
associatedDeclarationForContainingInitializerOrBindingName = location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindInferType:
|
||||||
|
if meaning&ast.SymbolFlagsTypeParameter != 0 {
|
||||||
|
parameterName := location.AsInferTypeNode().TypeParameter.AsTypeParameterDeclaration().Name()
|
||||||
|
if parameterName != nil && name == parameterName.Text() {
|
||||||
|
result = location.AsInferTypeNode().TypeParameter.Symbol()
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ast.KindExportSpecifier:
|
||||||
|
exportSpecifier := location.AsExportSpecifier()
|
||||||
|
if lastLocation != nil && lastLocation == exportSpecifier.PropertyName && location.Parent.Parent.ModuleSpecifier() != nil {
|
||||||
|
location = location.Parent.Parent.Parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isSelfReferenceLocation(location, lastLocation) {
|
||||||
|
lastSelfReferenceLocation = location
|
||||||
|
}
|
||||||
|
lastLocation = location
|
||||||
|
// !!! In Strada, JSDocTemplateTag/JSDocParameterTag/JSDocReturnTag locations skip to
|
||||||
|
// getEffectiveContainerForJSDocTemplateTag/getHostSignatureFromJSDoc instead of location.parent.
|
||||||
|
// This is a no-op currently because JSDoc nodes have no locals and getEffectiveJSDocHost is not
|
||||||
|
// fully ported for JS assignment patterns.
|
||||||
|
location = location.Parent
|
||||||
|
}
|
||||||
|
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
|
||||||
|
// If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself.
|
||||||
|
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
|
||||||
|
if isUse && result != nil && (lastSelfReferenceLocation == nil || result != lastSelfReferenceLocation.Symbol()) {
|
||||||
|
if r.SymbolReferenced != nil {
|
||||||
|
r.SymbolReferenced(result, meaning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if result == nil && !excludeGlobals {
|
||||||
|
result = r.lookup(r.Globals, name, meaning|ast.SymbolFlagsGlobalLookup)
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
if originalLocation != nil && ast.IsInJSFile(originalLocation) && originalLocation.Parent != nil {
|
||||||
|
if ast.IsRequireCall(originalLocation.Parent, false /*requireStringLiteralLikeArgument*/) {
|
||||||
|
return r.RequireSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nameNotFoundMessage != nil {
|
||||||
|
if propertyWithInvalidInitializer != nil && r.OnPropertyWithInvalidInitializer != nil && r.OnPropertyWithInvalidInitializer(originalLocation, name, propertyWithInvalidInitializer, result) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
if r.OnFailedToResolveSymbol != nil {
|
||||||
|
r.OnFailedToResolveSymbol(originalLocation, name, meaning, nameNotFoundMessage)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if r.OnSuccessfullyResolvedSymbol != nil {
|
||||||
|
r.OnSuccessfullyResolvedSymbol(originalLocation, result, meaning, lastLocation, associatedDeclarationForContainingInitializerOrBindingName, withinDeferredContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) useOuterVariableScopeInParameter(result *ast.Symbol, location *ast.Node, lastLocation *ast.Node) bool {
|
||||||
|
if ast.IsParameterDeclaration(lastLocation) {
|
||||||
|
body := location.Body()
|
||||||
|
if body != nil && result.ValueDeclaration != nil && result.ValueDeclaration.Pos() >= body.Pos() && result.ValueDeclaration.End() <= body.End() {
|
||||||
|
// check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body
|
||||||
|
// - static field in a class expression
|
||||||
|
// - optional chaining pre-es2020
|
||||||
|
// - nullish coalesce pre-es2020
|
||||||
|
// - spread assignment in binding pattern pre-es2017
|
||||||
|
functionLocation := location
|
||||||
|
declarationRequiresScopeChange := core.TSUnknown
|
||||||
|
if r.GetRequiresScopeChangeCache != nil {
|
||||||
|
declarationRequiresScopeChange = r.GetRequiresScopeChangeCache(functionLocation)
|
||||||
|
}
|
||||||
|
if declarationRequiresScopeChange == core.TSUnknown {
|
||||||
|
declarationRequiresScopeChange = core.IfElse(core.Some(functionLocation.Parameters(), r.requiresScopeChange), core.TSTrue, core.TSFalse)
|
||||||
|
if r.SetRequiresScopeChangeCache != nil {
|
||||||
|
r.SetRequiresScopeChangeCache(functionLocation, declarationRequiresScopeChange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return declarationRequiresScopeChange != core.TSTrue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) requiresScopeChange(node *ast.Node) bool {
|
||||||
|
d := node.AsParameterDeclaration()
|
||||||
|
return r.requiresScopeChangeWorker(d.Name()) || d.Initializer != nil && r.requiresScopeChangeWorker(d.Initializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) requiresScopeChangeWorker(node *ast.Node) bool {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindArrowFunction, ast.KindFunctionExpression, ast.KindFunctionDeclaration, ast.KindConstructor:
|
||||||
|
return false
|
||||||
|
case ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindPropertyAssignment:
|
||||||
|
return r.requiresScopeChangeWorker(node.Name())
|
||||||
|
case ast.KindPropertyDeclaration:
|
||||||
|
if ast.HasStaticModifier(node) {
|
||||||
|
return !r.CompilerOptions.GetEmitStandardClassFields()
|
||||||
|
}
|
||||||
|
return r.requiresScopeChangeWorker(node.AsPropertyDeclaration().Name())
|
||||||
|
default:
|
||||||
|
if ast.IsNullishCoalesce(node) || ast.IsOptionalChain(node) {
|
||||||
|
return r.CompilerOptions.GetEmitScriptTarget() < core.ScriptTargetES2020
|
||||||
|
}
|
||||||
|
if ast.IsBindingElement(node) && node.AsBindingElement().DotDotDotToken != nil && ast.IsObjectBindingPattern(node.Parent) {
|
||||||
|
return r.CompilerOptions.GetEmitScriptTarget() < core.ScriptTargetES2017
|
||||||
|
}
|
||||||
|
if ast.IsTypeNode(node) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return node.ForEachChild(r.requiresScopeChangeWorker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) error(location *ast.Node, message *diagnostics.Message, args ...any) {
|
||||||
|
if r.Error != nil {
|
||||||
|
r.Error(location, message, args...)
|
||||||
|
}
|
||||||
|
// Default implementation does not report errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) getSymbolOfDeclaration(node *ast.Node) *ast.Symbol {
|
||||||
|
if r.GetSymbolOfDeclaration != nil {
|
||||||
|
return r.GetSymbolOfDeclaration(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default implementation does not support merged symbols
|
||||||
|
return node.Symbol()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) lookup(symbols ast.SymbolTable, name string, meaning ast.SymbolFlags) *ast.Symbol {
|
||||||
|
if r.Lookup != nil {
|
||||||
|
return r.Lookup(symbols, name, meaning)
|
||||||
|
}
|
||||||
|
// Default implementation does not support following aliases or merged symbols
|
||||||
|
if meaning != 0 {
|
||||||
|
symbol := symbols[name]
|
||||||
|
if symbol != nil {
|
||||||
|
if symbol.Flags&meaning != 0 {
|
||||||
|
return symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NameResolver) argumentsSymbol() *ast.Symbol {
|
||||||
|
if r.ArgumentsSymbol == nil {
|
||||||
|
// Default implementation synthesizes a transient symbol for `arguments`
|
||||||
|
r.ArgumentsSymbol = &ast.Symbol{Name: "arguments", Flags: ast.SymbolFlagsProperty | ast.SymbolFlagsTransient}
|
||||||
|
}
|
||||||
|
return r.ArgumentsSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLocalSymbolForExportDefault(symbol *ast.Symbol) *ast.Symbol {
|
||||||
|
if !isExportDefaultSymbol(symbol) || len(symbol.Declarations) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, decl := range symbol.Declarations {
|
||||||
|
localSymbol := decl.LocalSymbol()
|
||||||
|
if localSymbol != nil {
|
||||||
|
return localSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isExportDefaultSymbol(symbol *ast.Symbol) bool {
|
||||||
|
return symbol != nil && len(symbol.Declarations) > 0 && ast.HasSyntacticModifier(symbol.Declarations[0], ast.ModifierFlagsDefault)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIsDeferredContext(location *ast.Node, lastLocation *ast.Node) bool {
|
||||||
|
if location.Kind != ast.KindArrowFunction && location.Kind != ast.KindFunctionExpression {
|
||||||
|
// initializers in instance property declaration of class like entities are executed in constructor and thus deferred
|
||||||
|
// A name is evaluated within the enclosing scope - so it shouldn't count as deferred
|
||||||
|
return ast.IsTypeQueryNode(location) ||
|
||||||
|
(ast.IsFunctionLikeDeclaration(location) || location.Kind == ast.KindPropertyDeclaration && !ast.IsStatic(location)) &&
|
||||||
|
(lastLocation == nil || lastLocation != location.Name())
|
||||||
|
}
|
||||||
|
if lastLocation != nil && lastLocation == location.Name() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// generator functions and async functions are not inlined in control flow when immediately invoked
|
||||||
|
if location.BodyData().AsteriskToken != nil || ast.HasSyntacticModifier(location, ast.ModifierFlagsAsync) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return ast.GetImmediatelyInvokedFunctionExpression(location) == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTypeParameterSymbolDeclaredInContainer(symbol *ast.Symbol, container *ast.Node) bool {
|
||||||
|
for _, decl := range symbol.Declarations {
|
||||||
|
if decl.Kind == ast.KindTypeParameter {
|
||||||
|
parent := decl.Parent
|
||||||
|
if parent == container {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSelfReferenceLocation(node *ast.Node, lastLocation *ast.Node) bool {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindParameter:
|
||||||
|
return lastLocation != nil && lastLocation == node.Name()
|
||||||
|
case ast.KindFunctionDeclaration, ast.KindClassDeclaration, ast.KindInterfaceDeclaration, ast.KindEnumDeclaration,
|
||||||
|
ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindModuleDeclaration: // For `namespace N { N; }`
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
262
tools/tsgo/internal/binder/referenceresolver.go
Normal file
262
tools/tsgo/internal/binder/referenceresolver.go
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
package binder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/microsoft/typescript-go/internal/ast"
|
||||||
|
"github.com/microsoft/typescript-go/internal/core"
|
||||||
|
"github.com/microsoft/typescript-go/internal/diagnostics"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReferenceResolver interface {
|
||||||
|
GetReferencedExportContainer(node *ast.IdentifierNode, prefixLocals bool) *ast.Node
|
||||||
|
GetReferencedImportDeclaration(node *ast.IdentifierNode) *ast.Declaration
|
||||||
|
GetReferencedValueDeclaration(node *ast.IdentifierNode) *ast.Declaration
|
||||||
|
GetReferencedValueDeclarations(node *ast.IdentifierNode) []*ast.Declaration
|
||||||
|
GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string
|
||||||
|
GetReferencedMemberValueDeclaration(node *ast.Node) *ast.Declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReferenceResolverHooks struct {
|
||||||
|
ResolveName func(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *ast.Symbol
|
||||||
|
GetResolvedSymbol func(*ast.Node) *ast.Symbol
|
||||||
|
GetMergedSymbol func(*ast.Symbol) *ast.Symbol
|
||||||
|
GetParentOfSymbol func(*ast.Symbol) *ast.Symbol
|
||||||
|
GetSymbolOfDeclaration func(*ast.Declaration) *ast.Symbol
|
||||||
|
GetTypeOnlyAliasDeclaration func(symbol *ast.Symbol, include ast.SymbolFlags) *ast.Declaration
|
||||||
|
GetExportSymbolOfValueSymbolIfExported func(*ast.Symbol) *ast.Symbol
|
||||||
|
GetElementAccessExpressionName func(*ast.ElementAccessExpression) (string, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ReferenceResolver = &referenceResolver{}
|
||||||
|
|
||||||
|
type referenceResolver struct {
|
||||||
|
resolver *NameResolver
|
||||||
|
options *core.CompilerOptions
|
||||||
|
hooks ReferenceResolverHooks
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReferenceResolver(options *core.CompilerOptions, hooks ReferenceResolverHooks) ReferenceResolver {
|
||||||
|
return &referenceResolver{
|
||||||
|
options: options,
|
||||||
|
hooks: hooks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getResolvedSymbol(node *ast.Node) *ast.Symbol {
|
||||||
|
if node != nil {
|
||||||
|
if r.hooks.GetResolvedSymbol != nil {
|
||||||
|
return r.hooks.GetResolvedSymbol(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getMergedSymbol(symbol *ast.Symbol) *ast.Symbol {
|
||||||
|
if symbol != nil {
|
||||||
|
if r.hooks.GetMergedSymbol != nil {
|
||||||
|
return r.hooks.GetMergedSymbol(symbol)
|
||||||
|
}
|
||||||
|
return symbol
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getParentOfSymbol(symbol *ast.Symbol) *ast.Symbol {
|
||||||
|
if symbol != nil {
|
||||||
|
if r.hooks.GetParentOfSymbol != nil {
|
||||||
|
return r.hooks.GetParentOfSymbol(symbol)
|
||||||
|
}
|
||||||
|
return symbol.Parent
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getSymbolOfDeclaration(declaration *ast.Declaration) *ast.Symbol {
|
||||||
|
if declaration != nil {
|
||||||
|
if r.hooks.GetSymbolOfDeclaration != nil {
|
||||||
|
return r.hooks.GetSymbolOfDeclaration(declaration)
|
||||||
|
}
|
||||||
|
return declaration.Symbol()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getReferencedValueSymbol(reference *ast.IdentifierNode, startInDeclarationContainer bool) *ast.Symbol {
|
||||||
|
resolvedSymbol := r.getResolvedSymbol(reference)
|
||||||
|
if resolvedSymbol != nil {
|
||||||
|
return resolvedSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
location := reference
|
||||||
|
if startInDeclarationContainer && reference.Parent != nil && ast.IsDeclaration(reference.Parent) && reference.Parent.Name() == reference {
|
||||||
|
location = ast.GetDeclarationContainer(reference.Parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.hooks.ResolveName != nil {
|
||||||
|
return r.hooks.ResolveName(location, reference.Text(), ast.SymbolFlagsExportValue|ast.SymbolFlagsValue|ast.SymbolFlagsAlias, nil /*nameNotFoundMessage*/, false /*isUse*/, false /*excludeGlobals*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.resolver == nil {
|
||||||
|
r.resolver = &NameResolver{
|
||||||
|
CompilerOptions: r.options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.resolver.Resolve(location, reference.Text(), ast.SymbolFlagsExportValue|ast.SymbolFlagsValue|ast.SymbolFlagsAlias, nil /*nameNotFoundMessage*/, false /*isUse*/, false /*excludeGlobals*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) isTypeOnlyAliasDeclaration(symbol *ast.Symbol) bool {
|
||||||
|
if symbol != nil {
|
||||||
|
if r.hooks.GetTypeOnlyAliasDeclaration != nil {
|
||||||
|
return r.hooks.GetTypeOnlyAliasDeclaration(symbol, ast.SymbolFlagsValue) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
node := r.getDeclarationOfAliasSymbol(symbol)
|
||||||
|
for node != nil {
|
||||||
|
switch node.Kind {
|
||||||
|
case ast.KindImportEqualsDeclaration, ast.KindExportDeclaration:
|
||||||
|
return node.IsTypeOnly()
|
||||||
|
case ast.KindImportClause, ast.KindImportSpecifier, ast.KindExportSpecifier:
|
||||||
|
if node.IsTypeOnly() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
node = node.Parent
|
||||||
|
continue
|
||||||
|
case ast.KindNamedImports, ast.KindNamedExports:
|
||||||
|
node = node.Parent
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getDeclarationOfAliasSymbol(symbol *ast.Symbol) *ast.Declaration {
|
||||||
|
return core.FindLast(symbol.Declarations, ast.IsAliasSymbolDeclaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) getExportSymbolOfValueSymbolIfExported(symbol *ast.Symbol) *ast.Symbol {
|
||||||
|
if symbol != nil {
|
||||||
|
if r.hooks.GetExportSymbolOfValueSymbolIfExported != nil {
|
||||||
|
return r.hooks.GetExportSymbolOfValueSymbolIfExported(symbol)
|
||||||
|
}
|
||||||
|
if symbol.Flags&ast.SymbolFlagsExportValue != 0 && symbol.ExportSymbol != nil {
|
||||||
|
symbol = symbol.ExportSymbol
|
||||||
|
}
|
||||||
|
return r.getMergedSymbol(symbol)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) GetReferencedExportContainer(node *ast.IdentifierNode, prefixLocals bool) *ast.Node /*SourceFile|ModuleDeclaration|EnumDeclaration*/ {
|
||||||
|
// When resolving the export for the name of a module or enum
|
||||||
|
// declaration, we need to start resolution at the declaration's container.
|
||||||
|
// Otherwise, we could incorrectly resolve the export as the
|
||||||
|
// declaration if it contains an exported member with the same name.
|
||||||
|
startInDeclarationContainer := node.Parent != nil && (node.Parent.Kind == ast.KindModuleDeclaration || node.Parent.Kind == ast.KindEnumDeclaration) && node == node.Parent.Name()
|
||||||
|
if symbol := r.getReferencedValueSymbol(node, startInDeclarationContainer); symbol != nil {
|
||||||
|
if symbol.Flags&ast.SymbolFlagsExportValue != 0 {
|
||||||
|
// If we reference an exported entity within the same module declaration, then whether
|
||||||
|
// we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the
|
||||||
|
// kinds that we do NOT prefix.
|
||||||
|
exportSymbol := r.getMergedSymbol(symbol.ExportSymbol)
|
||||||
|
if !prefixLocals && exportSymbol.Flags&ast.SymbolFlagsExportHasLocal != 0 && exportSymbol.Flags&ast.SymbolFlagsVariable == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
symbol = exportSymbol
|
||||||
|
}
|
||||||
|
parentSymbol := r.getParentOfSymbol(symbol)
|
||||||
|
if parentSymbol != nil {
|
||||||
|
if parentSymbol.Flags&ast.SymbolFlagsValueModule != 0 && parentSymbol.ValueDeclaration != nil && parentSymbol.ValueDeclaration.Kind == ast.KindSourceFile {
|
||||||
|
symbolFile := parentSymbol.ValueDeclaration.AsSourceFile()
|
||||||
|
referenceFile := ast.GetSourceFileOfNode(node)
|
||||||
|
// If `node` accesses an export and that export isn't in the same file, then symbol is a namespace export, so return nil.
|
||||||
|
symbolIsUmdExport := symbolFile != referenceFile
|
||||||
|
if symbolIsUmdExport {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return symbolFile.AsNode()
|
||||||
|
}
|
||||||
|
isMatchingContainer := func(n *ast.Node) bool {
|
||||||
|
return (n.Kind == ast.KindModuleDeclaration || n.Kind == ast.KindEnumDeclaration) && r.getSymbolOfDeclaration(n) == parentSymbol
|
||||||
|
}
|
||||||
|
return ast.FindAncestor(node.Parent, isMatchingContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) GetReferencedImportDeclaration(node *ast.IdentifierNode) *ast.Declaration {
|
||||||
|
if symbol := r.getReferencedValueSymbol(node, false /*startInDeclarationContainer*/); symbol != nil {
|
||||||
|
// We should only get the declaration of an alias if there isn't a local value
|
||||||
|
// declaration for the symbol
|
||||||
|
if ast.IsNonLocalAlias(symbol, ast.SymbolFlagsValue /*excludes*/) && !r.isTypeOnlyAliasDeclaration(symbol) {
|
||||||
|
return r.getDeclarationOfAliasSymbol(symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) GetReferencedValueDeclaration(node *ast.IdentifierNode) *ast.Declaration {
|
||||||
|
if symbol := r.getReferencedValueSymbol(node, false /*startInDeclarationContainer*/); symbol != nil {
|
||||||
|
return r.getExportSymbolOfValueSymbolIfExported(symbol).ValueDeclaration
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) GetReferencedValueDeclarations(node *ast.IdentifierNode) []*ast.Declaration {
|
||||||
|
var declarations []*ast.Declaration
|
||||||
|
if symbol := r.getReferencedValueSymbol(node, false /*startInDeclarationContainer*/); symbol != nil {
|
||||||
|
symbol = r.getExportSymbolOfValueSymbolIfExported(symbol)
|
||||||
|
for _, declaration := range symbol.Declarations {
|
||||||
|
switch declaration.Kind {
|
||||||
|
case ast.KindVariableDeclaration,
|
||||||
|
ast.KindParameter,
|
||||||
|
ast.KindBindingElement,
|
||||||
|
ast.KindPropertyDeclaration,
|
||||||
|
ast.KindPropertyAssignment,
|
||||||
|
ast.KindShorthandPropertyAssignment,
|
||||||
|
ast.KindEnumMember,
|
||||||
|
ast.KindObjectLiteralExpression,
|
||||||
|
ast.KindFunctionDeclaration,
|
||||||
|
ast.KindFunctionExpression,
|
||||||
|
ast.KindArrowFunction,
|
||||||
|
ast.KindClassDeclaration,
|
||||||
|
ast.KindClassExpression,
|
||||||
|
ast.KindEnumDeclaration,
|
||||||
|
ast.KindMethodDeclaration,
|
||||||
|
ast.KindGetAccessor,
|
||||||
|
ast.KindSetAccessor,
|
||||||
|
ast.KindModuleDeclaration:
|
||||||
|
declarations = append(declarations, declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return declarations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string {
|
||||||
|
if expression != nil {
|
||||||
|
if r.hooks.GetElementAccessExpressionName != nil {
|
||||||
|
if name, ok := r.hooks.GetElementAccessExpressionName(expression); ok {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *referenceResolver) GetReferencedMemberValueDeclaration(node *ast.Node) *ast.Declaration {
|
||||||
|
// member references are `this.something` or `this[something]`, so should always simply have a resolved symbol
|
||||||
|
s := r.getResolvedSymbol(node)
|
||||||
|
if s == nil && node.Symbol() != nil {
|
||||||
|
// might be a declaration instead of a ref, get the merged declaration symbol
|
||||||
|
s = r.getMergedSymbol(node.Symbol())
|
||||||
|
}
|
||||||
|
if s == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r.getExportSymbolOfValueSymbolIfExported(s).ValueDeclaration
|
||||||
|
}
|
||||||
53
tools/tsgo/internal/bundled/bundled.go
Normal file
53
tools/tsgo/internal/bundled/bundled.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Package bundled provides access to files bundled with TypeScript.
|
||||||
|
package bundled
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run generate.go
|
||||||
|
|
||||||
|
// Define the below here to consolidate documentation.
|
||||||
|
|
||||||
|
// Embedded is true if the bundled files are implemented through an embedded FS.
|
||||||
|
const Embedded = embedded
|
||||||
|
|
||||||
|
// WrapFS returns an FS which redirects embedded paths to the embedded file system.
|
||||||
|
// If the embedded file system is not available, it returns the original FS.
|
||||||
|
func WrapFS(fs vfs.FS) vfs.FS {
|
||||||
|
return wrapFS(fs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LibPath returns the path to the directory containing the bundled lib.d.ts files.
|
||||||
|
// If embedding is not enabled, this is a path on disk, and must be accessed through
|
||||||
|
// a real OS filesystem.
|
||||||
|
func LibPath() string {
|
||||||
|
return libPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
var bundledSourceDir = sync.OnceValue(func() string {
|
||||||
|
_, filename, _, ok := runtime.Caller(0)
|
||||||
|
if !ok {
|
||||||
|
panic("bundled: could not get current filename")
|
||||||
|
}
|
||||||
|
return filepath.Dir(filepath.FromSlash(filename))
|
||||||
|
})
|
||||||
|
|
||||||
|
var testingLibPath = sync.OnceValue(func() string {
|
||||||
|
if !testing.Testing() {
|
||||||
|
panic("bundled: TestingLibPath should only be called during tests")
|
||||||
|
}
|
||||||
|
return tspath.NormalizeSlashes(filepath.Join(bundledSourceDir(), "libs"))
|
||||||
|
})
|
||||||
|
|
||||||
|
// TestingLibPath returns the path to the source bundled libs directory.
|
||||||
|
// It's only valid to use in tests where the source code is available.
|
||||||
|
func TestingLibPath() string {
|
||||||
|
return testingLibPath()
|
||||||
|
}
|
||||||
48
tools/tsgo/internal/bundled/bundled_test.go
Normal file
48
tools/tsgo/internal/bundled/bundled_test.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package bundled_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/bundled"
|
||||||
|
"github.com/microsoft/typescript-go/internal/tspath"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs"
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTestingLibPath(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
p := bundled.TestingLibPath()
|
||||||
|
|
||||||
|
_, err := os.Stat(p)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
libdts := filepath.Join(p, "lib.d.ts")
|
||||||
|
|
||||||
|
_, err = os.Stat(libdts)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmbeddedLibs(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
fs := bundled.WrapFS(osvfs.FS())
|
||||||
|
|
||||||
|
var files []string
|
||||||
|
|
||||||
|
err := fs.WalkDir(bundled.LibPath(), func(path string, d vfs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !d.IsDir() {
|
||||||
|
files = append(files, tspath.GetBaseFileName(path))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
assert.DeepEqual(t, files, bundled.LibNames)
|
||||||
|
}
|
||||||
224
tools/tsgo/internal/bundled/embed.go
Normal file
224
tools/tsgo/internal/bundled/embed.go
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
//go:build !noembed
|
||||||
|
|
||||||
|
package bundled
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/vfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const embedded = true
|
||||||
|
|
||||||
|
const scheme = "bundled:///"
|
||||||
|
|
||||||
|
func splitPath(path string) (rest string, ok bool) {
|
||||||
|
return strings.CutPrefix(path, scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
func libPath() string {
|
||||||
|
return scheme + "libs"
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBundled(path string) bool {
|
||||||
|
_, ok := splitPath(path)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrappedFS is implemented directly rather than going through [io/fs.FS].
|
||||||
|
// Our vfs.FS works with file contents in terms of strings, and that's
|
||||||
|
// what go:embed does under the hood, but going through fs.FS will cause
|
||||||
|
// copying to []byte and back.
|
||||||
|
|
||||||
|
type wrappedFS struct {
|
||||||
|
fs vfs.FS
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ vfs.FS = (*wrappedFS)(nil)
|
||||||
|
|
||||||
|
func wrapFS(fs vfs.FS) vfs.FS {
|
||||||
|
return &wrappedFS{fs: fs}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) UseCaseSensitiveFileNames() bool {
|
||||||
|
return vfs.fs.UseCaseSensitiveFileNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) FileExists(path string) bool {
|
||||||
|
if rest, ok := splitPath(path); ok {
|
||||||
|
_, ok := embeddedContents[rest]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
return vfs.fs.FileExists(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) ReadFile(path string) (contents string, ok bool) {
|
||||||
|
if rest, ok := splitPath(path); ok {
|
||||||
|
contents, ok = embeddedContents[rest]
|
||||||
|
return contents, ok
|
||||||
|
}
|
||||||
|
return vfs.fs.ReadFile(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) DirectoryExists(path string) bool {
|
||||||
|
if rest, ok := splitPath(path); ok {
|
||||||
|
return rest == "libs"
|
||||||
|
}
|
||||||
|
return vfs.fs.DirectoryExists(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) GetAccessibleEntries(path string) (result vfs.Entries) {
|
||||||
|
if rest, ok := splitPath(path); ok {
|
||||||
|
if rest == "" {
|
||||||
|
result.Directories = []string{"libs"}
|
||||||
|
} else if rest == "libs" {
|
||||||
|
result.Files = LibNames
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return vfs.fs.GetAccessibleEntries(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootEntries = []fs.DirEntry{
|
||||||
|
fs.FileInfoToDirEntry(&fileInfo{name: "libs", mode: fs.ModeDir}),
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) Stat(path string) vfs.FileInfo {
|
||||||
|
if rest, ok := splitPath(path); ok {
|
||||||
|
if rest == "" || rest == "libs" {
|
||||||
|
return &fileInfo{name: rest, mode: fs.ModeDir}
|
||||||
|
}
|
||||||
|
if lib, ok := embeddedContents[rest]; ok {
|
||||||
|
libName, _ := strings.CutPrefix(rest, "libs/")
|
||||||
|
return &fileInfo{name: libName, size: int64(len(lib))}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return vfs.fs.Stat(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) WalkDir(root string, walkFn vfs.WalkDirFunc) error {
|
||||||
|
if rest, ok := splitPath(root); ok {
|
||||||
|
if err := vfs.walkDir(rest, walkFn); err != nil {
|
||||||
|
if err == fs.SkipAll { //nolint:errorlint
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return vfs.fs.WalkDir(root, walkFn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) walkDir(rest string, walkFn vfs.WalkDirFunc) error {
|
||||||
|
var entries []fs.DirEntry
|
||||||
|
switch rest {
|
||||||
|
case "":
|
||||||
|
entries = rootEntries
|
||||||
|
case "libs":
|
||||||
|
entries = libsEntries
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
name := rest + "/" + entry.Name()
|
||||||
|
|
||||||
|
if err := walkFn(scheme+name, entry, nil); err != nil {
|
||||||
|
if err == fs.SkipAll { //nolint:errorlint
|
||||||
|
return fs.SkipAll
|
||||||
|
}
|
||||||
|
if err == fs.SkipDir { //nolint:errorlint
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if entry.IsDir() {
|
||||||
|
if err := vfs.walkDir(strings.TrimPrefix(name, "/"), walkFn); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) Realpath(path string) string {
|
||||||
|
if _, ok := splitPath(path); ok {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return vfs.fs.Realpath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) WriteFile(path string, data string) error {
|
||||||
|
if _, ok := splitPath(path); ok {
|
||||||
|
panic("cannot write to embedded file system")
|
||||||
|
}
|
||||||
|
return vfs.fs.WriteFile(path, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) AppendFile(path string, data string) error {
|
||||||
|
if _, ok := splitPath(path); ok {
|
||||||
|
panic("cannot write to embedded file system")
|
||||||
|
}
|
||||||
|
return vfs.fs.AppendFile(path, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) Remove(path string) error {
|
||||||
|
if _, ok := splitPath(path); ok {
|
||||||
|
panic("cannot remove from embedded file system")
|
||||||
|
}
|
||||||
|
return vfs.fs.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vfs *wrappedFS) Chtimes(path string, aTime time.Time, mTime time.Time) error {
|
||||||
|
if _, ok := splitPath(path); ok {
|
||||||
|
panic("cannot change times on embedded file system")
|
||||||
|
}
|
||||||
|
return vfs.fs.Chtimes(path, aTime, mTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileInfo struct {
|
||||||
|
mode fs.FileMode
|
||||||
|
name string
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ fs.FileInfo = (*fileInfo)(nil)
|
||||||
|
_ fs.DirEntry = (*fileInfo)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (fi *fileInfo) IsDir() bool {
|
||||||
|
return fi.mode.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) ModTime() time.Time {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) Mode() fs.FileMode {
|
||||||
|
return fi.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) Name() string {
|
||||||
|
return fi.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) Size() int64 {
|
||||||
|
return fi.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) Sys() any {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) Info() (fs.FileInfo, error) {
|
||||||
|
return fi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fileInfo) Type() fs.FileMode {
|
||||||
|
return fi.mode.Type()
|
||||||
|
}
|
||||||
452
tools/tsgo/internal/bundled/embed_generated.go
Normal file
452
tools/tsgo/internal/bundled/embed_generated.go
Normal file
@@ -0,0 +1,452 @@
|
|||||||
|
//go:build !noembed
|
||||||
|
|
||||||
|
// Code generated by generate.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
package bundled
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed libs/lib.d.ts
|
||||||
|
libs_lib_d_ts string
|
||||||
|
//go:embed libs/lib.decorators.d.ts
|
||||||
|
libs_lib_decorators_d_ts string
|
||||||
|
//go:embed libs/lib.decorators.legacy.d.ts
|
||||||
|
libs_lib_decorators_legacy_d_ts string
|
||||||
|
//go:embed libs/lib.dom.asynciterable.d.ts
|
||||||
|
libs_lib_dom_asynciterable_d_ts string
|
||||||
|
//go:embed libs/lib.dom.d.ts
|
||||||
|
libs_lib_dom_d_ts string
|
||||||
|
//go:embed libs/lib.dom.iterable.d.ts
|
||||||
|
libs_lib_dom_iterable_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.collection.d.ts
|
||||||
|
libs_lib_es2015_collection_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.core.d.ts
|
||||||
|
libs_lib_es2015_core_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.d.ts
|
||||||
|
libs_lib_es2015_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.generator.d.ts
|
||||||
|
libs_lib_es2015_generator_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.iterable.d.ts
|
||||||
|
libs_lib_es2015_iterable_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.promise.d.ts
|
||||||
|
libs_lib_es2015_promise_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.proxy.d.ts
|
||||||
|
libs_lib_es2015_proxy_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.reflect.d.ts
|
||||||
|
libs_lib_es2015_reflect_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.symbol.d.ts
|
||||||
|
libs_lib_es2015_symbol_d_ts string
|
||||||
|
//go:embed libs/lib.es2015.symbol.wellknown.d.ts
|
||||||
|
libs_lib_es2015_symbol_wellknown_d_ts string
|
||||||
|
//go:embed libs/lib.es2016.array.include.d.ts
|
||||||
|
libs_lib_es2016_array_include_d_ts string
|
||||||
|
//go:embed libs/lib.es2016.d.ts
|
||||||
|
libs_lib_es2016_d_ts string
|
||||||
|
//go:embed libs/lib.es2016.full.d.ts
|
||||||
|
libs_lib_es2016_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2016.intl.d.ts
|
||||||
|
libs_lib_es2016_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.arraybuffer.d.ts
|
||||||
|
libs_lib_es2017_arraybuffer_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.d.ts
|
||||||
|
libs_lib_es2017_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.date.d.ts
|
||||||
|
libs_lib_es2017_date_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.full.d.ts
|
||||||
|
libs_lib_es2017_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.intl.d.ts
|
||||||
|
libs_lib_es2017_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.object.d.ts
|
||||||
|
libs_lib_es2017_object_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.sharedmemory.d.ts
|
||||||
|
libs_lib_es2017_sharedmemory_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.string.d.ts
|
||||||
|
libs_lib_es2017_string_d_ts string
|
||||||
|
//go:embed libs/lib.es2017.typedarrays.d.ts
|
||||||
|
libs_lib_es2017_typedarrays_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.asyncgenerator.d.ts
|
||||||
|
libs_lib_es2018_asyncgenerator_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.asynciterable.d.ts
|
||||||
|
libs_lib_es2018_asynciterable_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.d.ts
|
||||||
|
libs_lib_es2018_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.full.d.ts
|
||||||
|
libs_lib_es2018_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.intl.d.ts
|
||||||
|
libs_lib_es2018_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.promise.d.ts
|
||||||
|
libs_lib_es2018_promise_d_ts string
|
||||||
|
//go:embed libs/lib.es2018.regexp.d.ts
|
||||||
|
libs_lib_es2018_regexp_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.array.d.ts
|
||||||
|
libs_lib_es2019_array_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.d.ts
|
||||||
|
libs_lib_es2019_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.full.d.ts
|
||||||
|
libs_lib_es2019_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.intl.d.ts
|
||||||
|
libs_lib_es2019_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.object.d.ts
|
||||||
|
libs_lib_es2019_object_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.string.d.ts
|
||||||
|
libs_lib_es2019_string_d_ts string
|
||||||
|
//go:embed libs/lib.es2019.symbol.d.ts
|
||||||
|
libs_lib_es2019_symbol_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.bigint.d.ts
|
||||||
|
libs_lib_es2020_bigint_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.d.ts
|
||||||
|
libs_lib_es2020_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.date.d.ts
|
||||||
|
libs_lib_es2020_date_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.full.d.ts
|
||||||
|
libs_lib_es2020_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.intl.d.ts
|
||||||
|
libs_lib_es2020_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.number.d.ts
|
||||||
|
libs_lib_es2020_number_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.promise.d.ts
|
||||||
|
libs_lib_es2020_promise_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.sharedmemory.d.ts
|
||||||
|
libs_lib_es2020_sharedmemory_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.string.d.ts
|
||||||
|
libs_lib_es2020_string_d_ts string
|
||||||
|
//go:embed libs/lib.es2020.symbol.wellknown.d.ts
|
||||||
|
libs_lib_es2020_symbol_wellknown_d_ts string
|
||||||
|
//go:embed libs/lib.es2021.d.ts
|
||||||
|
libs_lib_es2021_d_ts string
|
||||||
|
//go:embed libs/lib.es2021.full.d.ts
|
||||||
|
libs_lib_es2021_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2021.intl.d.ts
|
||||||
|
libs_lib_es2021_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2021.promise.d.ts
|
||||||
|
libs_lib_es2021_promise_d_ts string
|
||||||
|
//go:embed libs/lib.es2021.string.d.ts
|
||||||
|
libs_lib_es2021_string_d_ts string
|
||||||
|
//go:embed libs/lib.es2021.weakref.d.ts
|
||||||
|
libs_lib_es2021_weakref_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.array.d.ts
|
||||||
|
libs_lib_es2022_array_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.d.ts
|
||||||
|
libs_lib_es2022_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.error.d.ts
|
||||||
|
libs_lib_es2022_error_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.full.d.ts
|
||||||
|
libs_lib_es2022_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.intl.d.ts
|
||||||
|
libs_lib_es2022_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.object.d.ts
|
||||||
|
libs_lib_es2022_object_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.regexp.d.ts
|
||||||
|
libs_lib_es2022_regexp_d_ts string
|
||||||
|
//go:embed libs/lib.es2022.string.d.ts
|
||||||
|
libs_lib_es2022_string_d_ts string
|
||||||
|
//go:embed libs/lib.es2023.array.d.ts
|
||||||
|
libs_lib_es2023_array_d_ts string
|
||||||
|
//go:embed libs/lib.es2023.collection.d.ts
|
||||||
|
libs_lib_es2023_collection_d_ts string
|
||||||
|
//go:embed libs/lib.es2023.d.ts
|
||||||
|
libs_lib_es2023_d_ts string
|
||||||
|
//go:embed libs/lib.es2023.full.d.ts
|
||||||
|
libs_lib_es2023_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2023.intl.d.ts
|
||||||
|
libs_lib_es2023_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.arraybuffer.d.ts
|
||||||
|
libs_lib_es2024_arraybuffer_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.collection.d.ts
|
||||||
|
libs_lib_es2024_collection_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.d.ts
|
||||||
|
libs_lib_es2024_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.full.d.ts
|
||||||
|
libs_lib_es2024_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.object.d.ts
|
||||||
|
libs_lib_es2024_object_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.promise.d.ts
|
||||||
|
libs_lib_es2024_promise_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.regexp.d.ts
|
||||||
|
libs_lib_es2024_regexp_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.sharedmemory.d.ts
|
||||||
|
libs_lib_es2024_sharedmemory_d_ts string
|
||||||
|
//go:embed libs/lib.es2024.string.d.ts
|
||||||
|
libs_lib_es2024_string_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.collection.d.ts
|
||||||
|
libs_lib_es2025_collection_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.d.ts
|
||||||
|
libs_lib_es2025_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.float16.d.ts
|
||||||
|
libs_lib_es2025_float16_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.full.d.ts
|
||||||
|
libs_lib_es2025_full_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.intl.d.ts
|
||||||
|
libs_lib_es2025_intl_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.iterator.d.ts
|
||||||
|
libs_lib_es2025_iterator_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.promise.d.ts
|
||||||
|
libs_lib_es2025_promise_d_ts string
|
||||||
|
//go:embed libs/lib.es2025.regexp.d.ts
|
||||||
|
libs_lib_es2025_regexp_d_ts string
|
||||||
|
//go:embed libs/lib.es5.d.ts
|
||||||
|
libs_lib_es5_d_ts string
|
||||||
|
//go:embed libs/lib.es6.d.ts
|
||||||
|
libs_lib_es6_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.array.d.ts
|
||||||
|
libs_lib_esnext_array_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.collection.d.ts
|
||||||
|
libs_lib_esnext_collection_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.d.ts
|
||||||
|
libs_lib_esnext_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.date.d.ts
|
||||||
|
libs_lib_esnext_date_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.decorators.d.ts
|
||||||
|
libs_lib_esnext_decorators_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.disposable.d.ts
|
||||||
|
libs_lib_esnext_disposable_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.error.d.ts
|
||||||
|
libs_lib_esnext_error_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.full.d.ts
|
||||||
|
libs_lib_esnext_full_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.intl.d.ts
|
||||||
|
libs_lib_esnext_intl_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.sharedmemory.d.ts
|
||||||
|
libs_lib_esnext_sharedmemory_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.temporal.d.ts
|
||||||
|
libs_lib_esnext_temporal_d_ts string
|
||||||
|
//go:embed libs/lib.esnext.typedarrays.d.ts
|
||||||
|
libs_lib_esnext_typedarrays_d_ts string
|
||||||
|
//go:embed libs/lib.scripthost.d.ts
|
||||||
|
libs_lib_scripthost_d_ts string
|
||||||
|
//go:embed libs/lib.webworker.asynciterable.d.ts
|
||||||
|
libs_lib_webworker_asynciterable_d_ts string
|
||||||
|
//go:embed libs/lib.webworker.d.ts
|
||||||
|
libs_lib_webworker_d_ts string
|
||||||
|
//go:embed libs/lib.webworker.importscripts.d.ts
|
||||||
|
libs_lib_webworker_importscripts_d_ts string
|
||||||
|
//go:embed libs/lib.webworker.iterable.d.ts
|
||||||
|
libs_lib_webworker_iterable_d_ts string
|
||||||
|
)
|
||||||
|
|
||||||
|
var embeddedContents = map[string]string{
|
||||||
|
"libs/lib.d.ts": libs_lib_d_ts,
|
||||||
|
"libs/lib.decorators.d.ts": libs_lib_decorators_d_ts,
|
||||||
|
"libs/lib.decorators.legacy.d.ts": libs_lib_decorators_legacy_d_ts,
|
||||||
|
"libs/lib.dom.asynciterable.d.ts": libs_lib_dom_asynciterable_d_ts,
|
||||||
|
"libs/lib.dom.d.ts": libs_lib_dom_d_ts,
|
||||||
|
"libs/lib.dom.iterable.d.ts": libs_lib_dom_iterable_d_ts,
|
||||||
|
"libs/lib.es2015.collection.d.ts": libs_lib_es2015_collection_d_ts,
|
||||||
|
"libs/lib.es2015.core.d.ts": libs_lib_es2015_core_d_ts,
|
||||||
|
"libs/lib.es2015.d.ts": libs_lib_es2015_d_ts,
|
||||||
|
"libs/lib.es2015.generator.d.ts": libs_lib_es2015_generator_d_ts,
|
||||||
|
"libs/lib.es2015.iterable.d.ts": libs_lib_es2015_iterable_d_ts,
|
||||||
|
"libs/lib.es2015.promise.d.ts": libs_lib_es2015_promise_d_ts,
|
||||||
|
"libs/lib.es2015.proxy.d.ts": libs_lib_es2015_proxy_d_ts,
|
||||||
|
"libs/lib.es2015.reflect.d.ts": libs_lib_es2015_reflect_d_ts,
|
||||||
|
"libs/lib.es2015.symbol.d.ts": libs_lib_es2015_symbol_d_ts,
|
||||||
|
"libs/lib.es2015.symbol.wellknown.d.ts": libs_lib_es2015_symbol_wellknown_d_ts,
|
||||||
|
"libs/lib.es2016.array.include.d.ts": libs_lib_es2016_array_include_d_ts,
|
||||||
|
"libs/lib.es2016.d.ts": libs_lib_es2016_d_ts,
|
||||||
|
"libs/lib.es2016.full.d.ts": libs_lib_es2016_full_d_ts,
|
||||||
|
"libs/lib.es2016.intl.d.ts": libs_lib_es2016_intl_d_ts,
|
||||||
|
"libs/lib.es2017.arraybuffer.d.ts": libs_lib_es2017_arraybuffer_d_ts,
|
||||||
|
"libs/lib.es2017.d.ts": libs_lib_es2017_d_ts,
|
||||||
|
"libs/lib.es2017.date.d.ts": libs_lib_es2017_date_d_ts,
|
||||||
|
"libs/lib.es2017.full.d.ts": libs_lib_es2017_full_d_ts,
|
||||||
|
"libs/lib.es2017.intl.d.ts": libs_lib_es2017_intl_d_ts,
|
||||||
|
"libs/lib.es2017.object.d.ts": libs_lib_es2017_object_d_ts,
|
||||||
|
"libs/lib.es2017.sharedmemory.d.ts": libs_lib_es2017_sharedmemory_d_ts,
|
||||||
|
"libs/lib.es2017.string.d.ts": libs_lib_es2017_string_d_ts,
|
||||||
|
"libs/lib.es2017.typedarrays.d.ts": libs_lib_es2017_typedarrays_d_ts,
|
||||||
|
"libs/lib.es2018.asyncgenerator.d.ts": libs_lib_es2018_asyncgenerator_d_ts,
|
||||||
|
"libs/lib.es2018.asynciterable.d.ts": libs_lib_es2018_asynciterable_d_ts,
|
||||||
|
"libs/lib.es2018.d.ts": libs_lib_es2018_d_ts,
|
||||||
|
"libs/lib.es2018.full.d.ts": libs_lib_es2018_full_d_ts,
|
||||||
|
"libs/lib.es2018.intl.d.ts": libs_lib_es2018_intl_d_ts,
|
||||||
|
"libs/lib.es2018.promise.d.ts": libs_lib_es2018_promise_d_ts,
|
||||||
|
"libs/lib.es2018.regexp.d.ts": libs_lib_es2018_regexp_d_ts,
|
||||||
|
"libs/lib.es2019.array.d.ts": libs_lib_es2019_array_d_ts,
|
||||||
|
"libs/lib.es2019.d.ts": libs_lib_es2019_d_ts,
|
||||||
|
"libs/lib.es2019.full.d.ts": libs_lib_es2019_full_d_ts,
|
||||||
|
"libs/lib.es2019.intl.d.ts": libs_lib_es2019_intl_d_ts,
|
||||||
|
"libs/lib.es2019.object.d.ts": libs_lib_es2019_object_d_ts,
|
||||||
|
"libs/lib.es2019.string.d.ts": libs_lib_es2019_string_d_ts,
|
||||||
|
"libs/lib.es2019.symbol.d.ts": libs_lib_es2019_symbol_d_ts,
|
||||||
|
"libs/lib.es2020.bigint.d.ts": libs_lib_es2020_bigint_d_ts,
|
||||||
|
"libs/lib.es2020.d.ts": libs_lib_es2020_d_ts,
|
||||||
|
"libs/lib.es2020.date.d.ts": libs_lib_es2020_date_d_ts,
|
||||||
|
"libs/lib.es2020.full.d.ts": libs_lib_es2020_full_d_ts,
|
||||||
|
"libs/lib.es2020.intl.d.ts": libs_lib_es2020_intl_d_ts,
|
||||||
|
"libs/lib.es2020.number.d.ts": libs_lib_es2020_number_d_ts,
|
||||||
|
"libs/lib.es2020.promise.d.ts": libs_lib_es2020_promise_d_ts,
|
||||||
|
"libs/lib.es2020.sharedmemory.d.ts": libs_lib_es2020_sharedmemory_d_ts,
|
||||||
|
"libs/lib.es2020.string.d.ts": libs_lib_es2020_string_d_ts,
|
||||||
|
"libs/lib.es2020.symbol.wellknown.d.ts": libs_lib_es2020_symbol_wellknown_d_ts,
|
||||||
|
"libs/lib.es2021.d.ts": libs_lib_es2021_d_ts,
|
||||||
|
"libs/lib.es2021.full.d.ts": libs_lib_es2021_full_d_ts,
|
||||||
|
"libs/lib.es2021.intl.d.ts": libs_lib_es2021_intl_d_ts,
|
||||||
|
"libs/lib.es2021.promise.d.ts": libs_lib_es2021_promise_d_ts,
|
||||||
|
"libs/lib.es2021.string.d.ts": libs_lib_es2021_string_d_ts,
|
||||||
|
"libs/lib.es2021.weakref.d.ts": libs_lib_es2021_weakref_d_ts,
|
||||||
|
"libs/lib.es2022.array.d.ts": libs_lib_es2022_array_d_ts,
|
||||||
|
"libs/lib.es2022.d.ts": libs_lib_es2022_d_ts,
|
||||||
|
"libs/lib.es2022.error.d.ts": libs_lib_es2022_error_d_ts,
|
||||||
|
"libs/lib.es2022.full.d.ts": libs_lib_es2022_full_d_ts,
|
||||||
|
"libs/lib.es2022.intl.d.ts": libs_lib_es2022_intl_d_ts,
|
||||||
|
"libs/lib.es2022.object.d.ts": libs_lib_es2022_object_d_ts,
|
||||||
|
"libs/lib.es2022.regexp.d.ts": libs_lib_es2022_regexp_d_ts,
|
||||||
|
"libs/lib.es2022.string.d.ts": libs_lib_es2022_string_d_ts,
|
||||||
|
"libs/lib.es2023.array.d.ts": libs_lib_es2023_array_d_ts,
|
||||||
|
"libs/lib.es2023.collection.d.ts": libs_lib_es2023_collection_d_ts,
|
||||||
|
"libs/lib.es2023.d.ts": libs_lib_es2023_d_ts,
|
||||||
|
"libs/lib.es2023.full.d.ts": libs_lib_es2023_full_d_ts,
|
||||||
|
"libs/lib.es2023.intl.d.ts": libs_lib_es2023_intl_d_ts,
|
||||||
|
"libs/lib.es2024.arraybuffer.d.ts": libs_lib_es2024_arraybuffer_d_ts,
|
||||||
|
"libs/lib.es2024.collection.d.ts": libs_lib_es2024_collection_d_ts,
|
||||||
|
"libs/lib.es2024.d.ts": libs_lib_es2024_d_ts,
|
||||||
|
"libs/lib.es2024.full.d.ts": libs_lib_es2024_full_d_ts,
|
||||||
|
"libs/lib.es2024.object.d.ts": libs_lib_es2024_object_d_ts,
|
||||||
|
"libs/lib.es2024.promise.d.ts": libs_lib_es2024_promise_d_ts,
|
||||||
|
"libs/lib.es2024.regexp.d.ts": libs_lib_es2024_regexp_d_ts,
|
||||||
|
"libs/lib.es2024.sharedmemory.d.ts": libs_lib_es2024_sharedmemory_d_ts,
|
||||||
|
"libs/lib.es2024.string.d.ts": libs_lib_es2024_string_d_ts,
|
||||||
|
"libs/lib.es2025.collection.d.ts": libs_lib_es2025_collection_d_ts,
|
||||||
|
"libs/lib.es2025.d.ts": libs_lib_es2025_d_ts,
|
||||||
|
"libs/lib.es2025.float16.d.ts": libs_lib_es2025_float16_d_ts,
|
||||||
|
"libs/lib.es2025.full.d.ts": libs_lib_es2025_full_d_ts,
|
||||||
|
"libs/lib.es2025.intl.d.ts": libs_lib_es2025_intl_d_ts,
|
||||||
|
"libs/lib.es2025.iterator.d.ts": libs_lib_es2025_iterator_d_ts,
|
||||||
|
"libs/lib.es2025.promise.d.ts": libs_lib_es2025_promise_d_ts,
|
||||||
|
"libs/lib.es2025.regexp.d.ts": libs_lib_es2025_regexp_d_ts,
|
||||||
|
"libs/lib.es5.d.ts": libs_lib_es5_d_ts,
|
||||||
|
"libs/lib.es6.d.ts": libs_lib_es6_d_ts,
|
||||||
|
"libs/lib.esnext.array.d.ts": libs_lib_esnext_array_d_ts,
|
||||||
|
"libs/lib.esnext.collection.d.ts": libs_lib_esnext_collection_d_ts,
|
||||||
|
"libs/lib.esnext.d.ts": libs_lib_esnext_d_ts,
|
||||||
|
"libs/lib.esnext.date.d.ts": libs_lib_esnext_date_d_ts,
|
||||||
|
"libs/lib.esnext.decorators.d.ts": libs_lib_esnext_decorators_d_ts,
|
||||||
|
"libs/lib.esnext.disposable.d.ts": libs_lib_esnext_disposable_d_ts,
|
||||||
|
"libs/lib.esnext.error.d.ts": libs_lib_esnext_error_d_ts,
|
||||||
|
"libs/lib.esnext.full.d.ts": libs_lib_esnext_full_d_ts,
|
||||||
|
"libs/lib.esnext.intl.d.ts": libs_lib_esnext_intl_d_ts,
|
||||||
|
"libs/lib.esnext.sharedmemory.d.ts": libs_lib_esnext_sharedmemory_d_ts,
|
||||||
|
"libs/lib.esnext.temporal.d.ts": libs_lib_esnext_temporal_d_ts,
|
||||||
|
"libs/lib.esnext.typedarrays.d.ts": libs_lib_esnext_typedarrays_d_ts,
|
||||||
|
"libs/lib.scripthost.d.ts": libs_lib_scripthost_d_ts,
|
||||||
|
"libs/lib.webworker.asynciterable.d.ts": libs_lib_webworker_asynciterable_d_ts,
|
||||||
|
"libs/lib.webworker.d.ts": libs_lib_webworker_d_ts,
|
||||||
|
"libs/lib.webworker.importscripts.d.ts": libs_lib_webworker_importscripts_d_ts,
|
||||||
|
"libs/lib.webworker.iterable.d.ts": libs_lib_webworker_iterable_d_ts,
|
||||||
|
}
|
||||||
|
|
||||||
|
var libsEntries = []fs.DirEntry{
|
||||||
|
&fileInfo{name: "lib.d.ts", size: int64(len(libs_lib_d_ts))},
|
||||||
|
&fileInfo{name: "lib.decorators.d.ts", size: int64(len(libs_lib_decorators_d_ts))},
|
||||||
|
&fileInfo{name: "lib.decorators.legacy.d.ts", size: int64(len(libs_lib_decorators_legacy_d_ts))},
|
||||||
|
&fileInfo{name: "lib.dom.asynciterable.d.ts", size: int64(len(libs_lib_dom_asynciterable_d_ts))},
|
||||||
|
&fileInfo{name: "lib.dom.d.ts", size: int64(len(libs_lib_dom_d_ts))},
|
||||||
|
&fileInfo{name: "lib.dom.iterable.d.ts", size: int64(len(libs_lib_dom_iterable_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.collection.d.ts", size: int64(len(libs_lib_es2015_collection_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.core.d.ts", size: int64(len(libs_lib_es2015_core_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.d.ts", size: int64(len(libs_lib_es2015_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.generator.d.ts", size: int64(len(libs_lib_es2015_generator_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.iterable.d.ts", size: int64(len(libs_lib_es2015_iterable_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.promise.d.ts", size: int64(len(libs_lib_es2015_promise_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.proxy.d.ts", size: int64(len(libs_lib_es2015_proxy_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.reflect.d.ts", size: int64(len(libs_lib_es2015_reflect_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.symbol.d.ts", size: int64(len(libs_lib_es2015_symbol_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2015.symbol.wellknown.d.ts", size: int64(len(libs_lib_es2015_symbol_wellknown_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2016.array.include.d.ts", size: int64(len(libs_lib_es2016_array_include_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2016.d.ts", size: int64(len(libs_lib_es2016_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2016.full.d.ts", size: int64(len(libs_lib_es2016_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2016.intl.d.ts", size: int64(len(libs_lib_es2016_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.arraybuffer.d.ts", size: int64(len(libs_lib_es2017_arraybuffer_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.d.ts", size: int64(len(libs_lib_es2017_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.date.d.ts", size: int64(len(libs_lib_es2017_date_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.full.d.ts", size: int64(len(libs_lib_es2017_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.intl.d.ts", size: int64(len(libs_lib_es2017_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.object.d.ts", size: int64(len(libs_lib_es2017_object_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.sharedmemory.d.ts", size: int64(len(libs_lib_es2017_sharedmemory_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.string.d.ts", size: int64(len(libs_lib_es2017_string_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2017.typedarrays.d.ts", size: int64(len(libs_lib_es2017_typedarrays_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.asyncgenerator.d.ts", size: int64(len(libs_lib_es2018_asyncgenerator_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.asynciterable.d.ts", size: int64(len(libs_lib_es2018_asynciterable_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.d.ts", size: int64(len(libs_lib_es2018_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.full.d.ts", size: int64(len(libs_lib_es2018_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.intl.d.ts", size: int64(len(libs_lib_es2018_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.promise.d.ts", size: int64(len(libs_lib_es2018_promise_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2018.regexp.d.ts", size: int64(len(libs_lib_es2018_regexp_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.array.d.ts", size: int64(len(libs_lib_es2019_array_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.d.ts", size: int64(len(libs_lib_es2019_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.full.d.ts", size: int64(len(libs_lib_es2019_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.intl.d.ts", size: int64(len(libs_lib_es2019_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.object.d.ts", size: int64(len(libs_lib_es2019_object_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.string.d.ts", size: int64(len(libs_lib_es2019_string_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2019.symbol.d.ts", size: int64(len(libs_lib_es2019_symbol_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.bigint.d.ts", size: int64(len(libs_lib_es2020_bigint_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.d.ts", size: int64(len(libs_lib_es2020_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.date.d.ts", size: int64(len(libs_lib_es2020_date_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.full.d.ts", size: int64(len(libs_lib_es2020_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.intl.d.ts", size: int64(len(libs_lib_es2020_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.number.d.ts", size: int64(len(libs_lib_es2020_number_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.promise.d.ts", size: int64(len(libs_lib_es2020_promise_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.sharedmemory.d.ts", size: int64(len(libs_lib_es2020_sharedmemory_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.string.d.ts", size: int64(len(libs_lib_es2020_string_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2020.symbol.wellknown.d.ts", size: int64(len(libs_lib_es2020_symbol_wellknown_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2021.d.ts", size: int64(len(libs_lib_es2021_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2021.full.d.ts", size: int64(len(libs_lib_es2021_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2021.intl.d.ts", size: int64(len(libs_lib_es2021_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2021.promise.d.ts", size: int64(len(libs_lib_es2021_promise_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2021.string.d.ts", size: int64(len(libs_lib_es2021_string_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2021.weakref.d.ts", size: int64(len(libs_lib_es2021_weakref_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.array.d.ts", size: int64(len(libs_lib_es2022_array_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.d.ts", size: int64(len(libs_lib_es2022_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.error.d.ts", size: int64(len(libs_lib_es2022_error_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.full.d.ts", size: int64(len(libs_lib_es2022_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.intl.d.ts", size: int64(len(libs_lib_es2022_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.object.d.ts", size: int64(len(libs_lib_es2022_object_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.regexp.d.ts", size: int64(len(libs_lib_es2022_regexp_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2022.string.d.ts", size: int64(len(libs_lib_es2022_string_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2023.array.d.ts", size: int64(len(libs_lib_es2023_array_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2023.collection.d.ts", size: int64(len(libs_lib_es2023_collection_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2023.d.ts", size: int64(len(libs_lib_es2023_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2023.full.d.ts", size: int64(len(libs_lib_es2023_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2023.intl.d.ts", size: int64(len(libs_lib_es2023_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.arraybuffer.d.ts", size: int64(len(libs_lib_es2024_arraybuffer_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.collection.d.ts", size: int64(len(libs_lib_es2024_collection_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.d.ts", size: int64(len(libs_lib_es2024_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.full.d.ts", size: int64(len(libs_lib_es2024_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.object.d.ts", size: int64(len(libs_lib_es2024_object_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.promise.d.ts", size: int64(len(libs_lib_es2024_promise_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.regexp.d.ts", size: int64(len(libs_lib_es2024_regexp_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.sharedmemory.d.ts", size: int64(len(libs_lib_es2024_sharedmemory_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2024.string.d.ts", size: int64(len(libs_lib_es2024_string_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.collection.d.ts", size: int64(len(libs_lib_es2025_collection_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.d.ts", size: int64(len(libs_lib_es2025_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.float16.d.ts", size: int64(len(libs_lib_es2025_float16_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.full.d.ts", size: int64(len(libs_lib_es2025_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.intl.d.ts", size: int64(len(libs_lib_es2025_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.iterator.d.ts", size: int64(len(libs_lib_es2025_iterator_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.promise.d.ts", size: int64(len(libs_lib_es2025_promise_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es2025.regexp.d.ts", size: int64(len(libs_lib_es2025_regexp_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es5.d.ts", size: int64(len(libs_lib_es5_d_ts))},
|
||||||
|
&fileInfo{name: "lib.es6.d.ts", size: int64(len(libs_lib_es6_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.array.d.ts", size: int64(len(libs_lib_esnext_array_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.collection.d.ts", size: int64(len(libs_lib_esnext_collection_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.d.ts", size: int64(len(libs_lib_esnext_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.date.d.ts", size: int64(len(libs_lib_esnext_date_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.decorators.d.ts", size: int64(len(libs_lib_esnext_decorators_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.disposable.d.ts", size: int64(len(libs_lib_esnext_disposable_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.error.d.ts", size: int64(len(libs_lib_esnext_error_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.full.d.ts", size: int64(len(libs_lib_esnext_full_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.intl.d.ts", size: int64(len(libs_lib_esnext_intl_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.sharedmemory.d.ts", size: int64(len(libs_lib_esnext_sharedmemory_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.temporal.d.ts", size: int64(len(libs_lib_esnext_temporal_d_ts))},
|
||||||
|
&fileInfo{name: "lib.esnext.typedarrays.d.ts", size: int64(len(libs_lib_esnext_typedarrays_d_ts))},
|
||||||
|
&fileInfo{name: "lib.scripthost.d.ts", size: int64(len(libs_lib_scripthost_d_ts))},
|
||||||
|
&fileInfo{name: "lib.webworker.asynciterable.d.ts", size: int64(len(libs_lib_webworker_asynciterable_d_ts))},
|
||||||
|
&fileInfo{name: "lib.webworker.d.ts", size: int64(len(libs_lib_webworker_d_ts))},
|
||||||
|
&fileInfo{name: "lib.webworker.importscripts.d.ts", size: int64(len(libs_lib_webworker_importscripts_d_ts))},
|
||||||
|
&fileInfo{name: "lib.webworker.iterable.d.ts", size: int64(len(libs_lib_webworker_iterable_d_ts))},
|
||||||
|
}
|
||||||
217
tools/tsgo/internal/bundled/generate.go
Normal file
217
tools/tsgo/internal/bundled/generate.go
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
//go:build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/microsoft/typescript-go/internal/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
libInputDir = filepath.Join(repo.TypeScriptSubmodulePath(), "src", "lib")
|
||||||
|
copyrightNotice = filepath.Join(repo.TypeScriptSubmodulePath(), "scripts", "CopyrightNotice.txt")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
|
||||||
|
libs := readLibs()
|
||||||
|
generateLibs(libs)
|
||||||
|
generateLibList(libs)
|
||||||
|
generateEmbedded(libs)
|
||||||
|
}
|
||||||
|
|
||||||
|
type lib struct {
|
||||||
|
target string // target relative to libs dir
|
||||||
|
sources []string // sources relative to src/lib dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateLibs(libs []lib) {
|
||||||
|
const outputDir = "libs"
|
||||||
|
|
||||||
|
copyright := readCopyright()
|
||||||
|
|
||||||
|
if err := os.RemoveAll(outputDir); err != nil {
|
||||||
|
log.Fatalf("failed to remove libs directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(outputDir, 0o755); err != nil {
|
||||||
|
log.Fatalf("failed to create libs directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, lib := range libs {
|
||||||
|
var output bytes.Buffer
|
||||||
|
output.Write(copyright)
|
||||||
|
|
||||||
|
for _, source := range lib.sources {
|
||||||
|
sourcePath := filepath.Join(libInputDir, source)
|
||||||
|
b, err := os.ReadFile(sourcePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to read %s: %v", sourcePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
output.WriteByte('\n')
|
||||||
|
output.Write(removeCRLF(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
outputPath := filepath.Join(outputDir, lib.target)
|
||||||
|
if err := os.WriteFile(outputPath, output.Bytes(), 0o644); err != nil {
|
||||||
|
log.Fatalf("failed to write %s: %v", outputPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateLibList(libs []lib) {
|
||||||
|
var code bytes.Buffer
|
||||||
|
code.WriteString("// Code generated by generate.go; DO NOT EDIT.\n\n")
|
||||||
|
code.WriteString("package bundled\n\n")
|
||||||
|
|
||||||
|
code.WriteString("// LibNames is the list of all bundled lib files, sorted by name.\n")
|
||||||
|
code.WriteString("// For the list of libs sorted by load order, use [tsoptions.Libs].\n")
|
||||||
|
code.WriteString("var LibNames = []string{\n")
|
||||||
|
for _, lib := range libs {
|
||||||
|
code.WriteString("\t\"" + lib.target + "\",\n")
|
||||||
|
}
|
||||||
|
code.WriteString("}\n")
|
||||||
|
|
||||||
|
writeCode("libs_generated.go", code.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateEmbedded(libs []lib) {
|
||||||
|
libVarNames := make([]string, len(libs))
|
||||||
|
for i, lib := range libs {
|
||||||
|
libVarNames[i] = "libs_" + strings.ReplaceAll(lib.target, ".", "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
var code bytes.Buffer
|
||||||
|
code.WriteString("//go:build !noembed\n\n")
|
||||||
|
code.WriteString("// Code generated by generate.go; DO NOT EDIT.\n\n")
|
||||||
|
code.WriteString("package bundled\n\n")
|
||||||
|
code.WriteString("import (\n")
|
||||||
|
code.WriteString("\"io/fs\"\n\n")
|
||||||
|
code.WriteString("_ \"embed\"\n")
|
||||||
|
code.WriteString(")\n\n")
|
||||||
|
|
||||||
|
code.WriteString("var (\n")
|
||||||
|
for i, lib := range libs {
|
||||||
|
varName := libVarNames[i]
|
||||||
|
code.WriteString("//go:embed libs/" + lib.target + "\n")
|
||||||
|
code.WriteString("" + varName + " string\n")
|
||||||
|
}
|
||||||
|
code.WriteString(")\n\n")
|
||||||
|
|
||||||
|
code.WriteString("var embeddedContents = map[string]string{\n")
|
||||||
|
for i, lib := range libs {
|
||||||
|
varName := libVarNames[i]
|
||||||
|
code.WriteString("\t\"libs/" + lib.target + "\": " + varName + ",\n")
|
||||||
|
}
|
||||||
|
code.WriteString("}\n\n")
|
||||||
|
|
||||||
|
code.WriteString("var libsEntries = []fs.DirEntry{\n")
|
||||||
|
for i, lib := range libs {
|
||||||
|
varName := libVarNames[i]
|
||||||
|
fmt.Fprintf(&code, "\t&fileInfo{name: %q, size: int64(len(%s))},\n", lib.target, varName)
|
||||||
|
}
|
||||||
|
code.WriteString("}\n")
|
||||||
|
|
||||||
|
writeCode("embed_generated.go", code.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Match escaped characters, double-quoted strings, single-line comments, and multi-line comments.
|
||||||
|
reJSONComments = regexp.MustCompile(`\\.|"(?:\\.|[^"])*"|//.*|/\*[\s\S]*?\*/`)
|
||||||
|
// Match double-quoted strings (to skip) or trailing commas before ] or }.
|
||||||
|
reTrailingComma = regexp.MustCompile(`"(?:\\.|[^"])*"|,\s*([}\]])`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// stripJSONC replaces comments and trailing commas with spaces in JSONC content,
|
||||||
|
// producing valid JSON. The input slice is mutated in place.
|
||||||
|
func stripJSONC(b []byte) {
|
||||||
|
for _, loc := range reJSONComments.FindAllIndex(b, -1) {
|
||||||
|
if b[loc[0]] == '/' {
|
||||||
|
for i := loc[0]; i < loc[1]; i++ {
|
||||||
|
if b[i] != '\n' {
|
||||||
|
b[i] = ' '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, loc := range reTrailingComma.FindAllSubmatchIndex(b, -1) {
|
||||||
|
// loc[2]:loc[3] is the capture group; -1 means this matched a string, not a comma.
|
||||||
|
if loc[2] < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Blank the comma (at loc[0]), keep whitespace and closing bracket.
|
||||||
|
b[loc[0]] = ' '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readLibs() []lib {
|
||||||
|
libsFile := filepath.Join(libInputDir, "libs.json")
|
||||||
|
|
||||||
|
b, err := os.ReadFile(libsFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to open libs.json: %v", err)
|
||||||
|
}
|
||||||
|
stripJSONC(b)
|
||||||
|
|
||||||
|
var meta struct {
|
||||||
|
Libs []string `json:"libs"`
|
||||||
|
Paths map[string]string `json:"paths"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &meta); err != nil {
|
||||||
|
log.Fatalf("failed to parse libs.json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var libs []lib
|
||||||
|
for _, libName := range meta.Libs {
|
||||||
|
sources := []string{libName + ".d.ts"}
|
||||||
|
var target string
|
||||||
|
if path, ok := meta.Paths[libName]; ok {
|
||||||
|
target = path
|
||||||
|
} else {
|
||||||
|
target = "lib." + libName + ".d.ts"
|
||||||
|
}
|
||||||
|
libs = append(libs, lib{target: target, sources: sources})
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(libs, func(a lib, b lib) int {
|
||||||
|
return strings.Compare(a.target, b.target)
|
||||||
|
})
|
||||||
|
|
||||||
|
return libs
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCopyright() []byte {
|
||||||
|
b, err := os.ReadFile(copyrightNotice)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to read copyright notice: %v", err)
|
||||||
|
}
|
||||||
|
return removeCRLF(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeCRLF(b []byte) []byte {
|
||||||
|
return bytes.ReplaceAll(b, []byte("\r\n"), []byte("\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeCode(filename string, code []byte) {
|
||||||
|
formatted, err := format.Source(code)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to format source: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(filename, formatted, 0o644); err != nil {
|
||||||
|
log.Fatalf("failed to write %s: %v", filename, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
20
tools/tsgo/internal/bundled/libs/lib.d.ts
vendored
Normal file
20
tools/tsgo/internal/bundled/libs/lib.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es5" />
|
||||||
|
/// <reference lib="dom" />
|
||||||
|
/// <reference lib="webworker.importscripts" />
|
||||||
|
/// <reference lib="scripthost" />
|
||||||
382
tools/tsgo/internal/bundled/libs/lib.decorators.d.ts
vendored
Normal file
382
tools/tsgo/internal/bundled/libs/lib.decorators.d.ts
vendored
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decorator context types provided to class element decorators.
|
||||||
|
*/
|
||||||
|
type ClassMemberDecoratorContext =
|
||||||
|
| ClassMethodDecoratorContext
|
||||||
|
| ClassGetterDecoratorContext
|
||||||
|
| ClassSetterDecoratorContext
|
||||||
|
| ClassFieldDecoratorContext
|
||||||
|
| ClassAccessorDecoratorContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decorator context types provided to any decorator.
|
||||||
|
*/
|
||||||
|
type DecoratorContext =
|
||||||
|
| ClassDecoratorContext
|
||||||
|
| ClassMemberDecoratorContext;
|
||||||
|
|
||||||
|
type DecoratorMetadataObject = Record<PropertyKey, unknown> & object;
|
||||||
|
|
||||||
|
type DecoratorMetadata = typeof globalThis extends { Symbol: { readonly metadata: symbol; }; } ? DecoratorMetadataObject : DecoratorMetadataObject | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to a class decorator.
|
||||||
|
* @template Class The type of the decorated class associated with this context.
|
||||||
|
*/
|
||||||
|
interface ClassDecoratorContext<
|
||||||
|
Class extends abstract new (...args: any) => any = abstract new (...args: any) => any,
|
||||||
|
> {
|
||||||
|
/** The kind of element that was decorated. */
|
||||||
|
readonly kind: "class";
|
||||||
|
|
||||||
|
/** The name of the decorated class. */
|
||||||
|
readonly name: string | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be invoked after the class definition has been finalized.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* function customElement(name: string): ClassDecoratorFunction {
|
||||||
|
* return (target, context) => {
|
||||||
|
* context.addInitializer(function () {
|
||||||
|
* customElements.define(name, this);
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @customElement("my-element")
|
||||||
|
* class MyElement {}
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
addInitializer(initializer: (this: Class) => void): void;
|
||||||
|
|
||||||
|
readonly metadata: DecoratorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to a class method decorator.
|
||||||
|
* @template This The type on which the class element will be defined. For a static class element, this will be
|
||||||
|
* the type of the constructor. For a non-static class element, this will be the type of the instance.
|
||||||
|
* @template Value The type of the decorated class method.
|
||||||
|
*/
|
||||||
|
interface ClassMethodDecoratorContext<
|
||||||
|
This = unknown,
|
||||||
|
Value extends (this: This, ...args: any) => any = (this: This, ...args: any) => any,
|
||||||
|
> {
|
||||||
|
/** The kind of class element that was decorated. */
|
||||||
|
readonly kind: "method";
|
||||||
|
|
||||||
|
/** The name of the decorated class element. */
|
||||||
|
readonly name: string | symbol;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element is a static (`true`) or instance (`false`) element. */
|
||||||
|
readonly static: boolean;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element has a private name. */
|
||||||
|
readonly private: boolean;
|
||||||
|
|
||||||
|
/** An object that can be used to access the current value of the class element at runtime. */
|
||||||
|
readonly access: {
|
||||||
|
/**
|
||||||
|
* Determines whether an object has a property with the same name as the decorated element.
|
||||||
|
*/
|
||||||
|
has(object: This): boolean;
|
||||||
|
/**
|
||||||
|
* Gets the current value of the method from the provided object.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* let fn = context.access.get(instance);
|
||||||
|
*/
|
||||||
|
get(object: This): Value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be invoked either after static methods are defined but before
|
||||||
|
* static initializers are run (when decorating a `static` element), or before instance
|
||||||
|
* initializers are run (when decorating a non-`static` element).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const bound: ClassMethodDecoratorFunction = (value, context) {
|
||||||
|
* if (context.private) throw new TypeError("Not supported on private methods.");
|
||||||
|
* context.addInitializer(function () {
|
||||||
|
* this[context.name] = this[context.name].bind(this);
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* class C {
|
||||||
|
* message = "Hello";
|
||||||
|
*
|
||||||
|
* @bound
|
||||||
|
* m() {
|
||||||
|
* console.log(this.message);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
addInitializer(initializer: (this: This) => void): void;
|
||||||
|
|
||||||
|
readonly metadata: DecoratorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to a class getter decorator.
|
||||||
|
* @template This The type on which the class element will be defined. For a static class element, this will be
|
||||||
|
* the type of the constructor. For a non-static class element, this will be the type of the instance.
|
||||||
|
* @template Value The property type of the decorated class getter.
|
||||||
|
*/
|
||||||
|
interface ClassGetterDecoratorContext<
|
||||||
|
This = unknown,
|
||||||
|
Value = unknown,
|
||||||
|
> {
|
||||||
|
/** The kind of class element that was decorated. */
|
||||||
|
readonly kind: "getter";
|
||||||
|
|
||||||
|
/** The name of the decorated class element. */
|
||||||
|
readonly name: string | symbol;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element is a static (`true`) or instance (`false`) element. */
|
||||||
|
readonly static: boolean;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element has a private name. */
|
||||||
|
readonly private: boolean;
|
||||||
|
|
||||||
|
/** An object that can be used to access the current value of the class element at runtime. */
|
||||||
|
readonly access: {
|
||||||
|
/**
|
||||||
|
* Determines whether an object has a property with the same name as the decorated element.
|
||||||
|
*/
|
||||||
|
has(object: This): boolean;
|
||||||
|
/**
|
||||||
|
* Invokes the getter on the provided object.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* let value = context.access.get(instance);
|
||||||
|
*/
|
||||||
|
get(object: This): Value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be invoked either after static methods are defined but before
|
||||||
|
* static initializers are run (when decorating a `static` element), or before instance
|
||||||
|
* initializers are run (when decorating a non-`static` element).
|
||||||
|
*/
|
||||||
|
addInitializer(initializer: (this: This) => void): void;
|
||||||
|
|
||||||
|
readonly metadata: DecoratorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to a class setter decorator.
|
||||||
|
* @template This The type on which the class element will be defined. For a static class element, this will be
|
||||||
|
* the type of the constructor. For a non-static class element, this will be the type of the instance.
|
||||||
|
* @template Value The type of the decorated class setter.
|
||||||
|
*/
|
||||||
|
interface ClassSetterDecoratorContext<
|
||||||
|
This = unknown,
|
||||||
|
Value = unknown,
|
||||||
|
> {
|
||||||
|
/** The kind of class element that was decorated. */
|
||||||
|
readonly kind: "setter";
|
||||||
|
|
||||||
|
/** The name of the decorated class element. */
|
||||||
|
readonly name: string | symbol;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element is a static (`true`) or instance (`false`) element. */
|
||||||
|
readonly static: boolean;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element has a private name. */
|
||||||
|
readonly private: boolean;
|
||||||
|
|
||||||
|
/** An object that can be used to access the current value of the class element at runtime. */
|
||||||
|
readonly access: {
|
||||||
|
/**
|
||||||
|
* Determines whether an object has a property with the same name as the decorated element.
|
||||||
|
*/
|
||||||
|
has(object: This): boolean;
|
||||||
|
/**
|
||||||
|
* Invokes the setter on the provided object.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* context.access.set(instance, value);
|
||||||
|
*/
|
||||||
|
set(object: This, value: Value): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be invoked either after static methods are defined but before
|
||||||
|
* static initializers are run (when decorating a `static` element), or before instance
|
||||||
|
* initializers are run (when decorating a non-`static` element).
|
||||||
|
*/
|
||||||
|
addInitializer(initializer: (this: This) => void): void;
|
||||||
|
|
||||||
|
readonly metadata: DecoratorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to a class `accessor` field decorator.
|
||||||
|
* @template This The type on which the class element will be defined. For a static class element, this will be
|
||||||
|
* the type of the constructor. For a non-static class element, this will be the type of the instance.
|
||||||
|
* @template Value The type of decorated class field.
|
||||||
|
*/
|
||||||
|
interface ClassAccessorDecoratorContext<
|
||||||
|
This = unknown,
|
||||||
|
Value = unknown,
|
||||||
|
> {
|
||||||
|
/** The kind of class element that was decorated. */
|
||||||
|
readonly kind: "accessor";
|
||||||
|
|
||||||
|
/** The name of the decorated class element. */
|
||||||
|
readonly name: string | symbol;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element is a static (`true`) or instance (`false`) element. */
|
||||||
|
readonly static: boolean;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element has a private name. */
|
||||||
|
readonly private: boolean;
|
||||||
|
|
||||||
|
/** An object that can be used to access the current value of the class element at runtime. */
|
||||||
|
readonly access: {
|
||||||
|
/**
|
||||||
|
* Determines whether an object has a property with the same name as the decorated element.
|
||||||
|
*/
|
||||||
|
has(object: This): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the getter on the provided object.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* let value = context.access.get(instance);
|
||||||
|
*/
|
||||||
|
get(object: This): Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the setter on the provided object.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* context.access.set(instance, value);
|
||||||
|
*/
|
||||||
|
set(object: This, value: Value): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be invoked immediately after the auto `accessor` being
|
||||||
|
* decorated is initialized (regardless if the `accessor` is `static` or not).
|
||||||
|
*/
|
||||||
|
addInitializer(initializer: (this: This) => void): void;
|
||||||
|
|
||||||
|
readonly metadata: DecoratorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the target provided to class `accessor` field decorators.
|
||||||
|
* @template This The `this` type to which the target applies.
|
||||||
|
* @template Value The property type for the class `accessor` field.
|
||||||
|
*/
|
||||||
|
interface ClassAccessorDecoratorTarget<This, Value> {
|
||||||
|
/**
|
||||||
|
* Invokes the getter that was defined prior to decorator application.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* let value = target.get.call(instance);
|
||||||
|
*/
|
||||||
|
get(this: This): Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the setter that was defined prior to decorator application.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* target.set.call(instance, value);
|
||||||
|
*/
|
||||||
|
set(this: This, value: Value): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the allowed return value from a class `accessor` field decorator.
|
||||||
|
* @template This The `this` type to which the target applies.
|
||||||
|
* @template Value The property type for the class `accessor` field.
|
||||||
|
*/
|
||||||
|
interface ClassAccessorDecoratorResult<This, Value> {
|
||||||
|
/**
|
||||||
|
* An optional replacement getter function. If not provided, the existing getter function is used instead.
|
||||||
|
*/
|
||||||
|
get?(this: This): Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional replacement setter function. If not provided, the existing setter function is used instead.
|
||||||
|
*/
|
||||||
|
set?(this: This, value: Value): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional initializer mutator that is invoked when the underlying field initializer is evaluated.
|
||||||
|
* @param value The incoming initializer value.
|
||||||
|
* @returns The replacement initializer value.
|
||||||
|
*/
|
||||||
|
init?(this: This, value: Value): Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to a class field decorator.
|
||||||
|
* @template This The type on which the class element will be defined. For a static class element, this will be
|
||||||
|
* the type of the constructor. For a non-static class element, this will be the type of the instance.
|
||||||
|
* @template Value The type of the decorated class field.
|
||||||
|
*/
|
||||||
|
interface ClassFieldDecoratorContext<
|
||||||
|
This = unknown,
|
||||||
|
Value = unknown,
|
||||||
|
> {
|
||||||
|
/** The kind of class element that was decorated. */
|
||||||
|
readonly kind: "field";
|
||||||
|
|
||||||
|
/** The name of the decorated class element. */
|
||||||
|
readonly name: string | symbol;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element is a static (`true`) or instance (`false`) element. */
|
||||||
|
readonly static: boolean;
|
||||||
|
|
||||||
|
/** A value indicating whether the class element has a private name. */
|
||||||
|
readonly private: boolean;
|
||||||
|
|
||||||
|
/** An object that can be used to access the current value of the class element at runtime. */
|
||||||
|
readonly access: {
|
||||||
|
/**
|
||||||
|
* Determines whether an object has a property with the same name as the decorated element.
|
||||||
|
*/
|
||||||
|
has(object: This): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the field on the provided object.
|
||||||
|
*/
|
||||||
|
get(object: This): Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the field on the provided object.
|
||||||
|
*/
|
||||||
|
set(object: This, value: Value): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be invoked immediately after the field being decorated
|
||||||
|
* is initialized (regardless if the field is `static` or not).
|
||||||
|
*/
|
||||||
|
addInitializer(initializer: (this: This) => void): void;
|
||||||
|
|
||||||
|
readonly metadata: DecoratorMetadata;
|
||||||
|
}
|
||||||
20
tools/tsgo/internal/bundled/libs/lib.decorators.legacy.d.ts
vendored
Normal file
20
tools/tsgo/internal/bundled/libs/lib.decorators.legacy.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
|
||||||
|
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
|
||||||
|
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
|
||||||
|
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void;
|
||||||
18
tools/tsgo/internal/bundled/libs/lib.dom.asynciterable.d.ts
vendored
Normal file
18
tools/tsgo/internal/bundled/libs/lib.dom.asynciterable.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
// This file's contents are now included in the main types file.
|
||||||
|
// The file has been left for backward compatibility.
|
||||||
45125
tools/tsgo/internal/bundled/libs/lib.dom.d.ts
vendored
Normal file
45125
tools/tsgo/internal/bundled/libs/lib.dom.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
tools/tsgo/internal/bundled/libs/lib.dom.iterable.d.ts
vendored
Normal file
18
tools/tsgo/internal/bundled/libs/lib.dom.iterable.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
// This file's contents are now included in the main types file.
|
||||||
|
// The file has been left for backward compatibility.
|
||||||
159
tools/tsgo/internal/bundled/libs/lib.es2015.collection.d.ts
vendored
Normal file
159
tools/tsgo/internal/bundled/libs/lib.es2015.collection.d.ts
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface Map<K, V> {
|
||||||
|
/**
|
||||||
|
* Removes all elements from the Map.
|
||||||
|
*/
|
||||||
|
clear(): void;
|
||||||
|
/**
|
||||||
|
* @returns true if an element in the Map existed and has been removed, or false if the element does not exist.
|
||||||
|
*/
|
||||||
|
delete(key: K): boolean;
|
||||||
|
/**
|
||||||
|
* Executes a provided function once per each key/value pair in the Map, in insertion order.
|
||||||
|
*/
|
||||||
|
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
|
||||||
|
/**
|
||||||
|
* Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
|
||||||
|
* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
|
||||||
|
*/
|
||||||
|
get(key: K): V | undefined;
|
||||||
|
/**
|
||||||
|
* @returns boolean indicating whether an element with the specified key exists or not.
|
||||||
|
*/
|
||||||
|
has(key: K): boolean;
|
||||||
|
/**
|
||||||
|
* Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
|
||||||
|
*/
|
||||||
|
set(key: K, value: V): this;
|
||||||
|
/**
|
||||||
|
* @returns the number of elements in the Map.
|
||||||
|
*/
|
||||||
|
readonly size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MapConstructor {
|
||||||
|
new (): Map<any, any>;
|
||||||
|
new <K, V>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>;
|
||||||
|
readonly prototype: Map<any, any>;
|
||||||
|
}
|
||||||
|
declare var Map: MapConstructor;
|
||||||
|
|
||||||
|
interface ReadonlyMap<K, V> {
|
||||||
|
forEach(callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void, thisArg?: any): void;
|
||||||
|
get(key: K): V | undefined;
|
||||||
|
has(key: K): boolean;
|
||||||
|
readonly size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakMap<K extends WeakKey, V> {
|
||||||
|
/**
|
||||||
|
* Removes the specified element from the WeakMap.
|
||||||
|
* @returns true if the element was successfully removed, or false if it was not present.
|
||||||
|
*/
|
||||||
|
delete(key: K): boolean;
|
||||||
|
/**
|
||||||
|
* @returns a specified element.
|
||||||
|
*/
|
||||||
|
get(key: K): V | undefined;
|
||||||
|
/**
|
||||||
|
* @returns a boolean indicating whether an element with the specified key exists or not.
|
||||||
|
*/
|
||||||
|
has(key: K): boolean;
|
||||||
|
/**
|
||||||
|
* Adds a new element with a specified key and value.
|
||||||
|
* @param key Must be an object or symbol.
|
||||||
|
*/
|
||||||
|
set(key: K, value: V): this;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakMapConstructor {
|
||||||
|
new <K extends WeakKey = WeakKey, V = any>(entries?: readonly (readonly [K, V])[] | null): WeakMap<K, V>;
|
||||||
|
readonly prototype: WeakMap<WeakKey, any>;
|
||||||
|
}
|
||||||
|
declare var WeakMap: WeakMapConstructor;
|
||||||
|
|
||||||
|
interface Set<T> {
|
||||||
|
/**
|
||||||
|
* Appends a new element with a specified value to the end of the Set.
|
||||||
|
*/
|
||||||
|
add(value: T): this;
|
||||||
|
/**
|
||||||
|
* Removes all elements from the Set.
|
||||||
|
*/
|
||||||
|
clear(): void;
|
||||||
|
/**
|
||||||
|
* Removes a specified value from the Set.
|
||||||
|
* @returns Returns true if an element in the Set existed and has been removed, or false if the element does not exist.
|
||||||
|
*/
|
||||||
|
delete(value: T): boolean;
|
||||||
|
/**
|
||||||
|
* Executes a provided function once per each value in the Set object, in insertion order.
|
||||||
|
*/
|
||||||
|
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void;
|
||||||
|
/**
|
||||||
|
* @returns a boolean indicating whether an element with the specified value exists in the Set or not.
|
||||||
|
*/
|
||||||
|
has(value: T): boolean;
|
||||||
|
/**
|
||||||
|
* @returns the number of (unique) elements in the Set.
|
||||||
|
*/
|
||||||
|
readonly size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SetConstructor {
|
||||||
|
new <T = any>(values?: readonly T[] | null): Set<T>;
|
||||||
|
readonly prototype: Set<any>;
|
||||||
|
}
|
||||||
|
declare var Set: SetConstructor;
|
||||||
|
|
||||||
|
interface ReadonlySet<T> {
|
||||||
|
/**
|
||||||
|
* Executes a provided function once per each value in the ReadonlySet object, in insertion order.
|
||||||
|
*/
|
||||||
|
forEach(callbackfn: (value: T, value2: T, set: ReadonlySet<T>) => void, thisArg?: any): void;
|
||||||
|
/**
|
||||||
|
* @returns a boolean indicating whether an element with the specified value exists in the Set or not.
|
||||||
|
*/
|
||||||
|
has(value: T): boolean;
|
||||||
|
/**
|
||||||
|
* @returns the number of (unique) elements in the Set.
|
||||||
|
*/
|
||||||
|
readonly size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakSet<T extends WeakKey> {
|
||||||
|
/**
|
||||||
|
* Appends a new value to the end of the WeakSet.
|
||||||
|
*/
|
||||||
|
add(value: T): this;
|
||||||
|
/**
|
||||||
|
* Removes the specified element from the WeakSet.
|
||||||
|
* @returns Returns true if the element existed and has been removed, or false if the element does not exist.
|
||||||
|
*/
|
||||||
|
delete(value: T): boolean;
|
||||||
|
/**
|
||||||
|
* @returns a boolean indicating whether a value exists in the WeakSet or not.
|
||||||
|
*/
|
||||||
|
has(value: T): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakSetConstructor {
|
||||||
|
new <T extends WeakKey = WeakKey>(values?: readonly T[] | null): WeakSet<T>;
|
||||||
|
readonly prototype: WeakSet<WeakKey>;
|
||||||
|
}
|
||||||
|
declare var WeakSet: WeakSetConstructor;
|
||||||
595
tools/tsgo/internal/bundled/libs/lib.es2015.core.d.ts
vendored
Normal file
595
tools/tsgo/internal/bundled/libs/lib.es2015.core.d.ts
vendored
Normal file
@@ -0,0 +1,595 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface Array<T> {
|
||||||
|
/**
|
||||||
|
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||||
|
* otherwise.
|
||||||
|
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||||
|
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||||
|
* immediately returns that element value. Otherwise, find returns undefined.
|
||||||
|
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||||
|
* predicate. If it is not provided, undefined is used instead.
|
||||||
|
*/
|
||||||
|
find<S extends T>(predicate: (value: T, index: number, obj: T[]) => value is S, thisArg?: any): S | undefined;
|
||||||
|
find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the first element in the array where predicate is true, and -1
|
||||||
|
* otherwise.
|
||||||
|
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||||
|
* order, until it finds one where predicate returns true. If such an element is found,
|
||||||
|
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
|
||||||
|
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||||
|
* predicate. If it is not provided, undefined is used instead.
|
||||||
|
*/
|
||||||
|
findIndex(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes all array elements from `start` to `end` index to a static `value` and returns the modified array
|
||||||
|
* @param value value to fill array section with
|
||||||
|
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||||
|
* length+start where length is the length of the array.
|
||||||
|
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||||
|
* length+end.
|
||||||
|
*/
|
||||||
|
fill(value: T, start?: number, end?: number): this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the this object after copying a section of the array identified by start and end
|
||||||
|
* to the same array starting at position target
|
||||||
|
* @param target If target is negative, it is treated as length+target where length is the
|
||||||
|
* length of the array.
|
||||||
|
* @param start If start is negative, it is treated as length+start. If end is negative, it
|
||||||
|
* is treated as length+end.
|
||||||
|
* @param end If not specified, length of the this object is used as its default value.
|
||||||
|
*/
|
||||||
|
copyWithin(target: number, start: number, end?: number): this;
|
||||||
|
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArrayConstructor {
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like object.
|
||||||
|
* @param arrayLike An array-like object to convert to an array.
|
||||||
|
*/
|
||||||
|
from<T>(arrayLike: ArrayLike<T>): T[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an iterable object.
|
||||||
|
* @param arrayLike An array-like object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new array from a set of elements.
|
||||||
|
* @param items A set of elements to include in the new array object.
|
||||||
|
*/
|
||||||
|
of<T>(...items: T[]): T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DateConstructor {
|
||||||
|
new (value: number | string | Date): Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Function {
|
||||||
|
/**
|
||||||
|
* Returns the name of the function. Function names are read-only and can not be changed.
|
||||||
|
*/
|
||||||
|
readonly name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Math {
|
||||||
|
/**
|
||||||
|
* Returns the number of leading zero bits in the 32-bit binary representation of a number.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
clz32(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of 32-bit multiplication of two numbers.
|
||||||
|
* @param x First number
|
||||||
|
* @param y Second number
|
||||||
|
*/
|
||||||
|
imul(x: number, y: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sign of x, indicating whether x is positive, negative, or zero.
|
||||||
|
* @param x The numeric expression to test
|
||||||
|
*/
|
||||||
|
sign(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base 10 logarithm of a number.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
log10(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base 2 logarithm of a number.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
log2(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the natural logarithm of 1 + x.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
log1p(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of (e^x - 1), which is an implementation-dependent approximation to
|
||||||
|
* subtracting 1 from the exponential function of x (e raised to the power of x, where e
|
||||||
|
* is the base of the natural logarithms).
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
expm1(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hyperbolic cosine of a number.
|
||||||
|
* @param x A numeric expression that contains an angle measured in radians.
|
||||||
|
*/
|
||||||
|
cosh(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hyperbolic sine of a number.
|
||||||
|
* @param x A numeric expression that contains an angle measured in radians.
|
||||||
|
*/
|
||||||
|
sinh(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hyperbolic tangent of a number.
|
||||||
|
* @param x A numeric expression that contains an angle measured in radians.
|
||||||
|
*/
|
||||||
|
tanh(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the inverse hyperbolic cosine of a number.
|
||||||
|
* @param x A numeric expression that contains an angle measured in radians.
|
||||||
|
*/
|
||||||
|
acosh(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the inverse hyperbolic sine of a number.
|
||||||
|
* @param x A numeric expression that contains an angle measured in radians.
|
||||||
|
*/
|
||||||
|
asinh(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the inverse hyperbolic tangent of a number.
|
||||||
|
* @param x A numeric expression that contains an angle measured in radians.
|
||||||
|
*/
|
||||||
|
atanh(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the square root of the sum of squares of its arguments.
|
||||||
|
* @param values Values to compute the square root for.
|
||||||
|
* If no arguments are passed, the result is +0.
|
||||||
|
* If there is only one argument, the result is the absolute value.
|
||||||
|
* If any argument is +Infinity or -Infinity, the result is +Infinity.
|
||||||
|
* If any argument is NaN, the result is NaN.
|
||||||
|
* If all arguments are either +0 or −0, the result is +0.
|
||||||
|
*/
|
||||||
|
hypot(...values: number[]): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the integral part of the numeric expression x, removing any fractional digits.
|
||||||
|
* If x is already an integer, the result is x.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
trunc(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nearest single precision float representation of a number.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
fround(x: number): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an implementation-dependent approximation to the cube root of number.
|
||||||
|
* @param x A numeric expression.
|
||||||
|
*/
|
||||||
|
cbrt(x: number): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NumberConstructor {
|
||||||
|
/**
|
||||||
|
* The value of Number.EPSILON is the difference between 1 and the smallest value greater than 1
|
||||||
|
* that is representable as a Number value, which is approximately:
|
||||||
|
* 2.2204460492503130808472633361816 x 10−16.
|
||||||
|
*/
|
||||||
|
readonly EPSILON: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if passed value is finite.
|
||||||
|
* Unlike the global isFinite, Number.isFinite doesn't forcibly convert the parameter to a
|
||||||
|
* number. Only finite values of the type number, result in true.
|
||||||
|
* @param number A numeric value.
|
||||||
|
*/
|
||||||
|
isFinite(number: unknown): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the value passed is an integer, false otherwise.
|
||||||
|
* @param number A numeric value.
|
||||||
|
*/
|
||||||
|
isInteger(number: unknown): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
|
||||||
|
* number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
|
||||||
|
* to a number. Only values of the type number, that are also NaN, result in true.
|
||||||
|
* @param number A numeric value.
|
||||||
|
*/
|
||||||
|
isNaN(number: unknown): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the value passed is a safe integer.
|
||||||
|
* @param number A numeric value.
|
||||||
|
*/
|
||||||
|
isSafeInteger(number: unknown): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of the largest integer n such that n and n + 1 are both exactly representable as
|
||||||
|
* a Number value.
|
||||||
|
* The value of Number.MAX_SAFE_INTEGER is 9007199254740991 2^53 − 1.
|
||||||
|
*/
|
||||||
|
readonly MAX_SAFE_INTEGER: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of the smallest integer n such that n and n − 1 are both exactly representable as
|
||||||
|
* a Number value.
|
||||||
|
* The value of Number.MIN_SAFE_INTEGER is −9007199254740991 (−(2^53 − 1)).
|
||||||
|
*/
|
||||||
|
readonly MIN_SAFE_INTEGER: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string to a floating-point number.
|
||||||
|
* @param string A string that contains a floating-point number.
|
||||||
|
*/
|
||||||
|
parseFloat(string: string): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts A string to an integer.
|
||||||
|
* @param string A string to convert into a number.
|
||||||
|
* @param radix A value between 2 and 36 that specifies the base of the number in `string`.
|
||||||
|
* If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
|
||||||
|
* All other strings are considered decimal.
|
||||||
|
*/
|
||||||
|
parseInt(string: string, radix?: number): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ObjectConstructor {
|
||||||
|
/**
|
||||||
|
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||||
|
* target object. Returns the target object.
|
||||||
|
* @param target The target object to copy to.
|
||||||
|
* @param source The source object from which to copy properties.
|
||||||
|
*/
|
||||||
|
assign<T extends {}, U>(target: T, source: U): T & U;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||||
|
* target object. Returns the target object.
|
||||||
|
* @param target The target object to copy to.
|
||||||
|
* @param source1 The first source object from which to copy properties.
|
||||||
|
* @param source2 The second source object from which to copy properties.
|
||||||
|
*/
|
||||||
|
assign<T extends {}, U, V>(target: T, source1: U, source2: V): T & U & V;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||||
|
* target object. Returns the target object.
|
||||||
|
* @param target The target object to copy to.
|
||||||
|
* @param source1 The first source object from which to copy properties.
|
||||||
|
* @param source2 The second source object from which to copy properties.
|
||||||
|
* @param source3 The third source object from which to copy properties.
|
||||||
|
*/
|
||||||
|
assign<T extends {}, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||||
|
* target object. Returns the target object.
|
||||||
|
* @param target The target object to copy to.
|
||||||
|
* @param sources One or more source objects from which to copy properties
|
||||||
|
*/
|
||||||
|
assign(target: object, ...sources: any[]): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all symbol properties found directly on object o.
|
||||||
|
* @param o Object to retrieve the symbols from.
|
||||||
|
*/
|
||||||
|
getOwnPropertySymbols(o: any): symbol[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of the enumerable string properties and methods of an object.
|
||||||
|
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||||
|
*/
|
||||||
|
keys(o: {}): string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the values are the same value, false otherwise.
|
||||||
|
* @param value1 The first value.
|
||||||
|
* @param value2 The second value.
|
||||||
|
*/
|
||||||
|
is(value1: any, value2: any): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the prototype of a specified object o to object proto or null. Returns the object o.
|
||||||
|
* @param o The object to change its prototype.
|
||||||
|
* @param proto The value of the new prototype or null.
|
||||||
|
*/
|
||||||
|
setPrototypeOf(o: any, proto: object | null): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadonlyArray<T> {
|
||||||
|
/**
|
||||||
|
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||||
|
* otherwise.
|
||||||
|
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||||
|
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||||
|
* immediately returns that element value. Otherwise, find returns undefined.
|
||||||
|
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||||
|
* predicate. If it is not provided, undefined is used instead.
|
||||||
|
*/
|
||||||
|
find<S extends T>(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined;
|
||||||
|
find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the first element in the array where predicate is true, and -1
|
||||||
|
* otherwise.
|
||||||
|
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||||
|
* order, until it finds one where predicate returns true. If such an element is found,
|
||||||
|
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
|
||||||
|
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||||
|
* predicate. If it is not provided, undefined is used instead.
|
||||||
|
*/
|
||||||
|
findIndex(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): number;
|
||||||
|
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegExp {
|
||||||
|
/**
|
||||||
|
* Returns a string indicating the flags of the regular expression in question. This field is read-only.
|
||||||
|
* The characters in this string are sequenced and concatenated in the following order:
|
||||||
|
*
|
||||||
|
* - "g" for global
|
||||||
|
* - "i" for ignoreCase
|
||||||
|
* - "m" for multiline
|
||||||
|
* - "u" for unicode
|
||||||
|
* - "y" for sticky
|
||||||
|
*
|
||||||
|
* If no flags are set, the value is the empty string.
|
||||||
|
*/
|
||||||
|
readonly flags: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Boolean value indicating the state of the sticky flag (y) used with a regular
|
||||||
|
* expression. Default is false. Read-only.
|
||||||
|
*/
|
||||||
|
readonly sticky: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Boolean value indicating the state of the Unicode flag (u) used with a regular
|
||||||
|
* expression. Default is false. Read-only.
|
||||||
|
*/
|
||||||
|
readonly unicode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegExpConstructor {
|
||||||
|
new (pattern: RegExp | string, flags?: string): RegExp;
|
||||||
|
(pattern: RegExp | string, flags?: string): RegExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface String {
|
||||||
|
/**
|
||||||
|
* Returns a nonnegative integer Number less than 1114112 (0x110000) that is the code point
|
||||||
|
* value of the UTF-16 encoded code point starting at the string element at position pos in
|
||||||
|
* the String resulting from converting this object to a String.
|
||||||
|
* If there is no element at that position, the result is undefined.
|
||||||
|
* If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.
|
||||||
|
*/
|
||||||
|
codePointAt(pos: number): number | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if searchString appears as a substring of the result of converting this
|
||||||
|
* object to a String, at one or more positions that are
|
||||||
|
* greater than or equal to position; otherwise, returns false.
|
||||||
|
* @param searchString search string
|
||||||
|
* @param position If position is undefined, 0 is assumed, so as to search all of the String.
|
||||||
|
*/
|
||||||
|
includes(searchString: string, position?: number): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||||
|
* same as the corresponding elements of this object (converted to a String) starting at
|
||||||
|
* endPosition – length(this). Otherwise returns false.
|
||||||
|
*/
|
||||||
|
endsWith(searchString: string, endPosition?: number): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the String value result of normalizing the string into the normalization form
|
||||||
|
* named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
|
||||||
|
* @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
|
||||||
|
* is "NFC"
|
||||||
|
*/
|
||||||
|
normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the String value result of normalizing the string into the normalization form
|
||||||
|
* named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
|
||||||
|
* @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
|
||||||
|
* is "NFC"
|
||||||
|
*/
|
||||||
|
normalize(form?: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a String value that is made from count copies appended together. If count is 0,
|
||||||
|
* the empty string is returned.
|
||||||
|
* @param count number of copies to append
|
||||||
|
*/
|
||||||
|
repeat(count: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||||
|
* same as the corresponding elements of this object (converted to a String) starting at
|
||||||
|
* position. Otherwise returns false.
|
||||||
|
*/
|
||||||
|
startsWith(searchString: string, position?: number): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an `<a>` HTML anchor element and sets the name attribute to the text value
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
anchor(name: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<big>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
big(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<blink>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
blink(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<b>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
bold(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<tt>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
fixed(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<font>` HTML element and sets the color attribute value
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
fontcolor(color: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<font>` HTML element and sets the size attribute value
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
fontsize(size: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<font>` HTML element and sets the size attribute value
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
fontsize(size: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an `<i>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
italics(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an `<a>` HTML element and sets the href attribute value
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
link(url: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<small>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
small(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<strike>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
strike(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<sub>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
sub(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<sup>` HTML element
|
||||||
|
* @deprecated A legacy feature for browser compatibility
|
||||||
|
*/
|
||||||
|
sup(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StringConstructor {
|
||||||
|
/**
|
||||||
|
* Return the String value whose elements are, in order, the elements in the List elements.
|
||||||
|
* If length is 0, the empty string is returned.
|
||||||
|
*/
|
||||||
|
fromCodePoint(...codePoints: number[]): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String.raw is usually used as a tag function of a Tagged Template String. When called as
|
||||||
|
* such, the first argument will be a well formed template call site object and the rest
|
||||||
|
* parameter will contain the substitution values. It can also be called directly, for example,
|
||||||
|
* to interleave strings and values from your own tag function, and in this case the only thing
|
||||||
|
* it needs from the first argument is the raw property.
|
||||||
|
* @param template A well-formed template string call site representation.
|
||||||
|
* @param substitutions A set of substitution values.
|
||||||
|
*/
|
||||||
|
raw(template: { raw: readonly string[] | ArrayLike<string>; }, ...substitutions: any[]): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8ClampedArray<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float64Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||||
|
}
|
||||||
26
tools/tsgo/internal/bundled/libs/lib.es2015.d.ts
vendored
Normal file
26
tools/tsgo/internal/bundled/libs/lib.es2015.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es5" />
|
||||||
|
/// <reference lib="es2015.core" />
|
||||||
|
/// <reference lib="es2015.collection" />
|
||||||
|
/// <reference lib="es2015.iterable" />
|
||||||
|
/// <reference lib="es2015.generator" />
|
||||||
|
/// <reference lib="es2015.promise" />
|
||||||
|
/// <reference lib="es2015.proxy" />
|
||||||
|
/// <reference lib="es2015.reflect" />
|
||||||
|
/// <reference lib="es2015.symbol" />
|
||||||
|
/// <reference lib="es2015.symbol.wellknown" />
|
||||||
75
tools/tsgo/internal/bundled/libs/lib.es2015.generator.d.ts
vendored
Normal file
75
tools/tsgo/internal/bundled/libs/lib.es2015.generator.d.ts
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2015.iterable" />
|
||||||
|
|
||||||
|
interface Generator<T = unknown, TReturn = any, TNext = any> extends IteratorObject<T, TReturn, TNext> {
|
||||||
|
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
||||||
|
next(...[value]: [] | [TNext]): IteratorResult<T, TReturn>;
|
||||||
|
return(value: TReturn): IteratorResult<T, TReturn>;
|
||||||
|
throw(e: any): IteratorResult<T, TReturn>;
|
||||||
|
[Symbol.iterator](): Generator<T, TReturn, TNext>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneratorFunction {
|
||||||
|
/**
|
||||||
|
* Creates a new Generator object.
|
||||||
|
* @param args A list of arguments the function accepts.
|
||||||
|
*/
|
||||||
|
new (...args: any[]): Generator;
|
||||||
|
/**
|
||||||
|
* Creates a new Generator object.
|
||||||
|
* @param args A list of arguments the function accepts.
|
||||||
|
*/
|
||||||
|
(...args: any[]): Generator;
|
||||||
|
/**
|
||||||
|
* The length of the arguments.
|
||||||
|
*/
|
||||||
|
readonly length: number;
|
||||||
|
/**
|
||||||
|
* Returns the name of the function.
|
||||||
|
*/
|
||||||
|
readonly name: string;
|
||||||
|
/**
|
||||||
|
* A reference to the prototype.
|
||||||
|
*/
|
||||||
|
readonly prototype: Generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneratorFunctionConstructor {
|
||||||
|
/**
|
||||||
|
* Creates a new Generator function.
|
||||||
|
* @param args A list of arguments the function accepts.
|
||||||
|
*/
|
||||||
|
new (...args: string[]): GeneratorFunction;
|
||||||
|
/**
|
||||||
|
* Creates a new Generator function.
|
||||||
|
* @param args A list of arguments the function accepts.
|
||||||
|
*/
|
||||||
|
(...args: string[]): GeneratorFunction;
|
||||||
|
/**
|
||||||
|
* The length of the arguments.
|
||||||
|
*/
|
||||||
|
readonly length: number;
|
||||||
|
/**
|
||||||
|
* Returns the name of the function.
|
||||||
|
*/
|
||||||
|
readonly name: string;
|
||||||
|
/**
|
||||||
|
* A reference to the prototype.
|
||||||
|
*/
|
||||||
|
readonly prototype: GeneratorFunction;
|
||||||
|
}
|
||||||
603
tools/tsgo/internal/bundled/libs/lib.es2015.iterable.d.ts
vendored
Normal file
603
tools/tsgo/internal/bundled/libs/lib.es2015.iterable.d.ts
vendored
Normal file
@@ -0,0 +1,603 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2015.symbol" />
|
||||||
|
|
||||||
|
interface SymbolConstructor {
|
||||||
|
/**
|
||||||
|
* A method that returns the default iterator for an object. Called by the semantics of the
|
||||||
|
* for-of statement.
|
||||||
|
*/
|
||||||
|
readonly iterator: unique symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IteratorYieldResult<TYield> {
|
||||||
|
done?: false;
|
||||||
|
value: TYield;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IteratorReturnResult<TReturn> {
|
||||||
|
done: true;
|
||||||
|
value: TReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
|
||||||
|
|
||||||
|
interface Iterator<T, TReturn = any, TNext = any> {
|
||||||
|
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
||||||
|
next(...[value]: [] | [TNext]): IteratorResult<T, TReturn>;
|
||||||
|
return?(value?: TReturn): IteratorResult<T, TReturn>;
|
||||||
|
throw?(e?: any): IteratorResult<T, TReturn>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Iterable<T, TReturn = any, TNext = any> {
|
||||||
|
[Symbol.iterator](): Iterator<T, TReturn, TNext>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes a user-defined {@link Iterator} that is also iterable.
|
||||||
|
*/
|
||||||
|
interface IterableIterator<T, TReturn = any, TNext = any> extends Iterator<T, TReturn, TNext> {
|
||||||
|
[Symbol.iterator](): IterableIterator<T, TReturn, TNext>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes an {@link Iterator} produced by the runtime that inherits from the intrinsic `Iterator.prototype`.
|
||||||
|
*/
|
||||||
|
interface IteratorObject<T, TReturn = unknown, TNext = unknown> extends Iterator<T, TReturn, TNext> {
|
||||||
|
[Symbol.iterator](): IteratorObject<T, TReturn, TNext>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the `TReturn` type used for built-in iterators produced by `Array`, `Map`, `Set`, and others.
|
||||||
|
* This is `undefined` when `strictBuiltInIteratorReturn` is `true`; otherwise, this is `any`.
|
||||||
|
*/
|
||||||
|
type BuiltinIteratorReturn = intrinsic;
|
||||||
|
|
||||||
|
interface ArrayIterator<T> extends IteratorObject<T, BuiltinIteratorReturn, unknown> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Array<T> {
|
||||||
|
/** Iterator */
|
||||||
|
[Symbol.iterator](): ArrayIterator<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, T]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArrayConstructor {
|
||||||
|
/**
|
||||||
|
* Creates an array from an iterable object.
|
||||||
|
* @param iterable An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from<T>(iterable: Iterable<T> | ArrayLike<T>): T[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an iterable object.
|
||||||
|
* @param iterable An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadonlyArray<T> {
|
||||||
|
/** Iterator of values in the array. */
|
||||||
|
[Symbol.iterator](): ArrayIterator<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, T]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IArguments {
|
||||||
|
/** Iterator */
|
||||||
|
[Symbol.iterator](): ArrayIterator<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MapIterator<T> extends IteratorObject<T, BuiltinIteratorReturn, unknown> {
|
||||||
|
[Symbol.iterator](): MapIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Map<K, V> {
|
||||||
|
/** Returns an iterable of entries in the map. */
|
||||||
|
[Symbol.iterator](): MapIterator<[K, V]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of key, value pairs for every entry in the map.
|
||||||
|
*/
|
||||||
|
entries(): MapIterator<[K, V]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of keys in the map
|
||||||
|
*/
|
||||||
|
keys(): MapIterator<K>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of values in the map
|
||||||
|
*/
|
||||||
|
values(): MapIterator<V>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadonlyMap<K, V> {
|
||||||
|
/** Returns an iterable of entries in the map. */
|
||||||
|
[Symbol.iterator](): MapIterator<[K, V]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of key, value pairs for every entry in the map.
|
||||||
|
*/
|
||||||
|
entries(): MapIterator<[K, V]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of keys in the map
|
||||||
|
*/
|
||||||
|
keys(): MapIterator<K>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of values in the map
|
||||||
|
*/
|
||||||
|
values(): MapIterator<V>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MapConstructor {
|
||||||
|
new (): Map<any, any>;
|
||||||
|
new <K, V>(iterable?: Iterable<readonly [K, V]> | null): Map<K, V>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakMap<K extends WeakKey, V> {}
|
||||||
|
|
||||||
|
interface WeakMapConstructor {
|
||||||
|
new <K extends WeakKey = WeakKey, V = any>(iterable?: Iterable<readonly [K, V]> | null): WeakMap<K, V>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SetIterator<T> extends IteratorObject<T, BuiltinIteratorReturn, unknown> {
|
||||||
|
[Symbol.iterator](): SetIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Set<T> {
|
||||||
|
/** Iterates over values in the set. */
|
||||||
|
[Symbol.iterator](): SetIterator<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of [v,v] pairs for every value `v` in the set.
|
||||||
|
*/
|
||||||
|
entries(): SetIterator<[T, T]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Despite its name, returns an iterable of the values in the set.
|
||||||
|
*/
|
||||||
|
keys(): SetIterator<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of values in the set.
|
||||||
|
*/
|
||||||
|
values(): SetIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadonlySet<T> {
|
||||||
|
/** Iterates over values in the set. */
|
||||||
|
[Symbol.iterator](): SetIterator<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of [v,v] pairs for every value `v` in the set.
|
||||||
|
*/
|
||||||
|
entries(): SetIterator<[T, T]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Despite its name, returns an iterable of the values in the set.
|
||||||
|
*/
|
||||||
|
keys(): SetIterator<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterable of values in the set.
|
||||||
|
*/
|
||||||
|
values(): SetIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SetConstructor {
|
||||||
|
new <T>(iterable?: Iterable<T> | null): Set<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakSet<T extends WeakKey> {}
|
||||||
|
|
||||||
|
interface WeakSetConstructor {
|
||||||
|
new <T extends WeakKey = WeakKey>(iterable: Iterable<T>): WeakSet<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Promise<T> {}
|
||||||
|
|
||||||
|
interface PromiseConstructor {
|
||||||
|
/**
|
||||||
|
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||||
|
* resolve, or rejected when any Promise is rejected.
|
||||||
|
* @param values An iterable of Promises.
|
||||||
|
* @returns A new Promise.
|
||||||
|
*/
|
||||||
|
all<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
|
||||||
|
* or rejected.
|
||||||
|
* @param values An iterable of Promises.
|
||||||
|
* @returns A new Promise.
|
||||||
|
*/
|
||||||
|
race<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StringIterator<T> extends IteratorObject<T, BuiltinIteratorReturn, unknown> {
|
||||||
|
[Symbol.iterator](): StringIterator<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface String {
|
||||||
|
/** Iterator */
|
||||||
|
[Symbol.iterator](): StringIterator<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int8ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Int8Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Int8Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Int8Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Uint8Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Uint8Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint8Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8ClampedArray<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8ClampedArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Uint8ClampedArray<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Uint8ClampedArray<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint8ClampedArray<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int16ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Int16Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Int16Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Int16Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint16ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Uint16Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Uint16Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint16Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int32ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Int32Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Int32Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Int32Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint32ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Uint32Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Uint32Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Uint32Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float32ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Float32Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Float32Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Float32Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float64Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
[Symbol.iterator](): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of key, value pairs for every entry in the array
|
||||||
|
*/
|
||||||
|
entries(): ArrayIterator<[number, number]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of keys in the array
|
||||||
|
*/
|
||||||
|
keys(): ArrayIterator<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an list of values in the array
|
||||||
|
*/
|
||||||
|
values(): ArrayIterator<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float64ArrayConstructor {
|
||||||
|
new (elements: Iterable<number>): Float64Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
*/
|
||||||
|
from(elements: Iterable<number>): Float64Array<ArrayBuffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array from an array-like or iterable object.
|
||||||
|
* @param elements An iterable object to convert to an array.
|
||||||
|
* @param mapfn A mapping function to call on every element of the array.
|
||||||
|
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||||
|
*/
|
||||||
|
from<T>(elements: Iterable<T>, mapfn?: (v: T, k: number) => number, thisArg?: any): Float64Array<ArrayBuffer>;
|
||||||
|
}
|
||||||
79
tools/tsgo/internal/bundled/libs/lib.es2015.promise.d.ts
vendored
Normal file
79
tools/tsgo/internal/bundled/libs/lib.es2015.promise.d.ts
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface PromiseConstructor {
|
||||||
|
/**
|
||||||
|
* A reference to the prototype.
|
||||||
|
*/
|
||||||
|
readonly prototype: Promise<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Promise.
|
||||||
|
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
||||||
|
* a resolve callback used to resolve the promise with a value or the result of another promise,
|
||||||
|
* and a reject callback used to reject the promise with a provided reason or error.
|
||||||
|
*/
|
||||||
|
new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||||
|
* resolve, or rejected when any Promise is rejected.
|
||||||
|
* @param values An array of Promises.
|
||||||
|
* @returns A new Promise.
|
||||||
|
*/
|
||||||
|
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]>; }>;
|
||||||
|
|
||||||
|
// see: lib.es2015.iterable.d.ts
|
||||||
|
// all<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
|
||||||
|
* or rejected.
|
||||||
|
* @param values An array of Promises.
|
||||||
|
* @returns A new Promise.
|
||||||
|
*/
|
||||||
|
race<T extends readonly unknown[] | []>(values: T): Promise<Awaited<T[number]>>;
|
||||||
|
|
||||||
|
// see: lib.es2015.iterable.d.ts
|
||||||
|
// race<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new rejected promise for the provided reason.
|
||||||
|
* @param reason The reason the promise was rejected.
|
||||||
|
* @returns A new rejected Promise.
|
||||||
|
*/
|
||||||
|
reject<T = never>(reason?: any): Promise<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new resolved promise.
|
||||||
|
* @returns A resolved promise.
|
||||||
|
*/
|
||||||
|
resolve(): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Creates a new resolved promise for the provided value.
|
||||||
|
* @param value A promise.
|
||||||
|
* @returns A promise whose internal state matches the provided promise.
|
||||||
|
*/
|
||||||
|
resolve<T>(value: T): Promise<Awaited<T>>;
|
||||||
|
/**
|
||||||
|
* Creates a new resolved promise for the provided value.
|
||||||
|
* @param value A promise.
|
||||||
|
* @returns A promise whose internal state matches the provided promise.
|
||||||
|
*/
|
||||||
|
resolve<T>(value: T | PromiseLike<T>): Promise<Awaited<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Promise: PromiseConstructor;
|
||||||
126
tools/tsgo/internal/bundled/libs/lib.es2015.proxy.d.ts
vendored
Normal file
126
tools/tsgo/internal/bundled/libs/lib.es2015.proxy.d.ts
vendored
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface ProxyHandler<T extends object> {
|
||||||
|
/**
|
||||||
|
* A trap method for a function call.
|
||||||
|
* @param target The original callable object which is being proxied.
|
||||||
|
*/
|
||||||
|
apply?(target: T, thisArg: any, argArray: any[]): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for the `new` operator.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param newTarget The constructor that was originally called.
|
||||||
|
*/
|
||||||
|
construct?(target: T, argArray: any[], newTarget: Function): object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for `Object.defineProperty()`.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @returns A `Boolean` indicating whether or not the property has been defined.
|
||||||
|
*/
|
||||||
|
defineProperty?(target: T, property: string | symbol, attributes: PropertyDescriptor): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for the `delete` operator.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param p The name or `Symbol` of the property to delete.
|
||||||
|
* @returns A `Boolean` indicating whether or not the property was deleted.
|
||||||
|
*/
|
||||||
|
deleteProperty?(target: T, p: string | symbol): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for getting a property value.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param p The name or `Symbol` of the property to get.
|
||||||
|
* @param receiver The proxy or an object that inherits from the proxy.
|
||||||
|
*/
|
||||||
|
get?(target: T, p: string | symbol, receiver: any): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for `Object.getOwnPropertyDescriptor()`.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param p The name of the property whose description should be retrieved.
|
||||||
|
*/
|
||||||
|
getOwnPropertyDescriptor?(target: T, p: string | symbol): PropertyDescriptor | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for the `[[GetPrototypeOf]]` internal method.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
*/
|
||||||
|
getPrototypeOf?(target: T): object | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for the `in` operator.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param p The name or `Symbol` of the property to check for existence.
|
||||||
|
*/
|
||||||
|
has?(target: T, p: string | symbol): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for `Object.isExtensible()`.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
*/
|
||||||
|
isExtensible?(target: T): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for `Reflect.ownKeys()`.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
*/
|
||||||
|
ownKeys?(target: T): ArrayLike<string | symbol>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for `Object.preventExtensions()`.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
*/
|
||||||
|
preventExtensions?(target: T): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for setting a property value.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param p The name or `Symbol` of the property to set.
|
||||||
|
* @param receiver The object to which the assignment was originally directed.
|
||||||
|
* @returns A `Boolean` indicating whether or not the property was set.
|
||||||
|
*/
|
||||||
|
set?(target: T, p: string | symbol, newValue: any, receiver: any): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for `Object.setPrototypeOf()`.
|
||||||
|
* @param target The original object which is being proxied.
|
||||||
|
* @param newPrototype The object's new prototype or `null`.
|
||||||
|
*/
|
||||||
|
setPrototypeOf?(target: T, v: object | null): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProxyConstructor {
|
||||||
|
/**
|
||||||
|
* Creates a revocable Proxy object.
|
||||||
|
* @param target A target object to wrap with Proxy.
|
||||||
|
* @param handler An object whose properties define the behavior of Proxy when an operation is attempted on it.
|
||||||
|
*/
|
||||||
|
revocable<T extends object>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Proxy object. The Proxy object allows you to create an object that can be used in place of the
|
||||||
|
* original object, but which may redefine fundamental Object operations like getting, setting, and defining
|
||||||
|
* properties. Proxy objects are commonly used to log property accesses, validate, format, or sanitize inputs.
|
||||||
|
* @param target A target object to wrap with Proxy.
|
||||||
|
* @param handler An object whose properties define the behavior of Proxy when an operation is attempted on it.
|
||||||
|
*/
|
||||||
|
new <T extends object>(target: T, handler: ProxyHandler<T>): T;
|
||||||
|
}
|
||||||
|
declare var Proxy: ProxyConstructor;
|
||||||
142
tools/tsgo/internal/bundled/libs/lib.es2015.reflect.d.ts
vendored
Normal file
142
tools/tsgo/internal/bundled/libs/lib.es2015.reflect.d.ts
vendored
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
declare namespace Reflect {
|
||||||
|
/**
|
||||||
|
* Calls the function with the specified object as the this value
|
||||||
|
* and the elements of specified array as the arguments.
|
||||||
|
* @param target The function to call.
|
||||||
|
* @param thisArgument The object to be used as the this object.
|
||||||
|
* @param argumentsList An array of argument values to be passed to the function.
|
||||||
|
*/
|
||||||
|
function apply<T, A extends readonly any[], R>(
|
||||||
|
target: (this: T, ...args: A) => R,
|
||||||
|
thisArgument: T,
|
||||||
|
argumentsList: Readonly<A>,
|
||||||
|
): R;
|
||||||
|
function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the target with the elements of specified array as the arguments
|
||||||
|
* and the specified constructor as the `new.target` value.
|
||||||
|
* @param target The constructor to invoke.
|
||||||
|
* @param argumentsList An array of argument values to be passed to the constructor.
|
||||||
|
* @param newTarget The constructor to be used as the `new.target` object.
|
||||||
|
*/
|
||||||
|
function construct<A extends readonly any[], R>(
|
||||||
|
target: new (...args: A) => R,
|
||||||
|
argumentsList: Readonly<A>,
|
||||||
|
newTarget?: new (...args: any) => any,
|
||||||
|
): R;
|
||||||
|
function construct(target: Function, argumentsList: ArrayLike<any>, newTarget?: Function): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a property to an object, or modifies attributes of an existing property.
|
||||||
|
* @param target Object on which to add or modify the property. This can be a native JavaScript object
|
||||||
|
* (that is, a user-defined object or a built in object) or a DOM object.
|
||||||
|
* @param propertyKey The property name.
|
||||||
|
* @param attributes Descriptor for the property. It can be for a data property or an accessor property.
|
||||||
|
*/
|
||||||
|
function defineProperty(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor & ThisType<any>): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a property from an object, equivalent to `delete target[propertyKey]`,
|
||||||
|
* except it won't throw if `target[propertyKey]` is non-configurable.
|
||||||
|
* @param target Object from which to remove the own property.
|
||||||
|
* @param propertyKey The property name.
|
||||||
|
*/
|
||||||
|
function deleteProperty(target: object, propertyKey: PropertyKey): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the property of target, equivalent to `target[propertyKey]` when `receiver === target`.
|
||||||
|
* @param target Object that contains the property on itself or in its prototype chain.
|
||||||
|
* @param propertyKey The property name.
|
||||||
|
* @param receiver The reference to use as the `this` value in the getter function,
|
||||||
|
* if `target[propertyKey]` is an accessor property.
|
||||||
|
*/
|
||||||
|
function get<T extends object, P extends PropertyKey>(
|
||||||
|
target: T,
|
||||||
|
propertyKey: P,
|
||||||
|
receiver?: unknown,
|
||||||
|
): P extends keyof T ? T[P] : any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the own property descriptor of the specified object.
|
||||||
|
* An own property descriptor is one that is defined directly on the object and is not inherited from the object's prototype.
|
||||||
|
* @param target Object that contains the property.
|
||||||
|
* @param propertyKey The property name.
|
||||||
|
*/
|
||||||
|
function getOwnPropertyDescriptor<T extends object, P extends PropertyKey>(
|
||||||
|
target: T,
|
||||||
|
propertyKey: P,
|
||||||
|
): TypedPropertyDescriptor<P extends keyof T ? T[P] : any> | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the prototype of an object.
|
||||||
|
* @param target The object that references the prototype.
|
||||||
|
*/
|
||||||
|
function getPrototypeOf(target: object): object | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to `propertyKey in target`.
|
||||||
|
* @param target Object that contains the property on itself or in its prototype chain.
|
||||||
|
* @param propertyKey Name of the property.
|
||||||
|
*/
|
||||||
|
function has(target: object, propertyKey: PropertyKey): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value that indicates whether new properties can be added to an object.
|
||||||
|
* @param target Object to test.
|
||||||
|
*/
|
||||||
|
function isExtensible(target: object): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string and symbol keys of the own properties of an object. The own properties of an object
|
||||||
|
* are those that are defined directly on that object, and are not inherited from the object's prototype.
|
||||||
|
* @param target Object that contains the own properties.
|
||||||
|
*/
|
||||||
|
function ownKeys(target: object): (string | symbol)[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevents the addition of new properties to an object.
|
||||||
|
* @param target Object to make non-extensible.
|
||||||
|
* @return Whether the object has been made non-extensible.
|
||||||
|
*/
|
||||||
|
function preventExtensions(target: object): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the property of target, equivalent to `target[propertyKey] = value` when `receiver === target`.
|
||||||
|
* @param target Object that contains the property on itself or in its prototype chain.
|
||||||
|
* @param propertyKey Name of the property.
|
||||||
|
* @param receiver The reference to use as the `this` value in the setter function,
|
||||||
|
* if `target[propertyKey]` is an accessor property.
|
||||||
|
*/
|
||||||
|
function set<T extends object, P extends PropertyKey>(
|
||||||
|
target: T,
|
||||||
|
propertyKey: P,
|
||||||
|
value: P extends keyof T ? T[P] : any,
|
||||||
|
receiver?: any,
|
||||||
|
): boolean;
|
||||||
|
function set(target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the prototype of a specified object o to object proto or null.
|
||||||
|
* @param target The object to change its prototype.
|
||||||
|
* @param proto The value of the new prototype or null.
|
||||||
|
* @return Whether setting the prototype was successful.
|
||||||
|
*/
|
||||||
|
function setPrototypeOf(target: object, proto: object | null): boolean;
|
||||||
|
}
|
||||||
44
tools/tsgo/internal/bundled/libs/lib.es2015.symbol.d.ts
vendored
Normal file
44
tools/tsgo/internal/bundled/libs/lib.es2015.symbol.d.ts
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface SymbolConstructor {
|
||||||
|
/**
|
||||||
|
* A reference to the prototype.
|
||||||
|
*/
|
||||||
|
readonly prototype: Symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new unique Symbol value.
|
||||||
|
* @param description Description of the new Symbol object.
|
||||||
|
*/
|
||||||
|
(description?: string | number): symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Symbol object from the global symbol registry matching the given key if found.
|
||||||
|
* Otherwise, returns a new symbol with this key.
|
||||||
|
* @param key key to search for.
|
||||||
|
*/
|
||||||
|
for(key: string): symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a key from the global symbol registry matching the given Symbol if found.
|
||||||
|
* Otherwise, returns undefined.
|
||||||
|
* @param sym Symbol to find the key for.
|
||||||
|
*/
|
||||||
|
keyFor(sym: symbol): string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var Symbol: SymbolConstructor;
|
||||||
324
tools/tsgo/internal/bundled/libs/lib.es2015.symbol.wellknown.d.ts
vendored
Normal file
324
tools/tsgo/internal/bundled/libs/lib.es2015.symbol.wellknown.d.ts
vendored
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2015.symbol" />
|
||||||
|
|
||||||
|
interface SymbolConstructor {
|
||||||
|
/**
|
||||||
|
* A method that determines if a constructor object recognizes an object as one of the
|
||||||
|
* constructor’s instances. Called by the semantics of the instanceof operator.
|
||||||
|
*/
|
||||||
|
readonly hasInstance: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Boolean value that if true indicates that an object should flatten to its array elements
|
||||||
|
* by Array.prototype.concat.
|
||||||
|
*/
|
||||||
|
readonly isConcatSpreadable: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A regular expression method that matches the regular expression against a string. Called
|
||||||
|
* by the String.prototype.match method.
|
||||||
|
*/
|
||||||
|
readonly match: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A regular expression method that replaces matched substrings of a string. Called by the
|
||||||
|
* String.prototype.replace method.
|
||||||
|
*/
|
||||||
|
readonly replace: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A regular expression method that returns the index within a string that matches the
|
||||||
|
* regular expression. Called by the String.prototype.search method.
|
||||||
|
*/
|
||||||
|
readonly search: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function valued property that is the constructor function that is used to create
|
||||||
|
* derived objects.
|
||||||
|
*/
|
||||||
|
readonly species: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A regular expression method that splits a string at the indices that match the regular
|
||||||
|
* expression. Called by the String.prototype.split method.
|
||||||
|
*/
|
||||||
|
readonly split: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that converts an object to a corresponding primitive value.
|
||||||
|
* Called by the ToPrimitive abstract operation.
|
||||||
|
*/
|
||||||
|
readonly toPrimitive: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A String value that is used in the creation of the default string description of an object.
|
||||||
|
* Called by the built-in method Object.prototype.toString.
|
||||||
|
*/
|
||||||
|
readonly toStringTag: unique symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Object whose truthy properties are properties that are excluded from the 'with'
|
||||||
|
* environment bindings of the associated objects.
|
||||||
|
*/
|
||||||
|
readonly unscopables: unique symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Symbol {
|
||||||
|
/**
|
||||||
|
* Converts a Symbol object to a symbol.
|
||||||
|
*/
|
||||||
|
[Symbol.toPrimitive](hint: string): symbol;
|
||||||
|
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Array<T> {
|
||||||
|
/**
|
||||||
|
* Is an object whose properties have the value 'true'
|
||||||
|
* when they will be absent when used in a 'with' statement.
|
||||||
|
*/
|
||||||
|
readonly [Symbol.unscopables]: {
|
||||||
|
[K in keyof any[]]?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadonlyArray<T> {
|
||||||
|
/**
|
||||||
|
* Is an object whose properties have the value 'true'
|
||||||
|
* when they will be absent when used in a 'with' statement.
|
||||||
|
*/
|
||||||
|
readonly [Symbol.unscopables]: {
|
||||||
|
[K in keyof readonly any[]]?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Date {
|
||||||
|
/**
|
||||||
|
* Converts a Date object to a string.
|
||||||
|
*/
|
||||||
|
[Symbol.toPrimitive](hint: "default"): string;
|
||||||
|
/**
|
||||||
|
* Converts a Date object to a string.
|
||||||
|
*/
|
||||||
|
[Symbol.toPrimitive](hint: "string"): string;
|
||||||
|
/**
|
||||||
|
* Converts a Date object to a number.
|
||||||
|
*/
|
||||||
|
[Symbol.toPrimitive](hint: "number"): number;
|
||||||
|
/**
|
||||||
|
* Converts a Date object to a string or number.
|
||||||
|
*
|
||||||
|
* @param hint The strings "number", "string", or "default" to specify what primitive to return.
|
||||||
|
*
|
||||||
|
* @throws {TypeError} If 'hint' was given something other than "number", "string", or "default".
|
||||||
|
* @returns A number if 'hint' was "number", a string if 'hint' was "string" or "default".
|
||||||
|
*/
|
||||||
|
[Symbol.toPrimitive](hint: string): string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Map<K, V> {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakMap<K extends WeakKey, V> {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Set<T> {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeakSet<T extends WeakKey> {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JSON {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Function {
|
||||||
|
/**
|
||||||
|
* Determines whether the given value inherits from this function if this function was used
|
||||||
|
* as a constructor function.
|
||||||
|
*
|
||||||
|
* A constructor function can control which objects are recognized as its instances by
|
||||||
|
* 'instanceof' by overriding this method.
|
||||||
|
*/
|
||||||
|
[Symbol.hasInstance](value: any): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneratorFunction {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Math {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Promise<T> {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PromiseConstructor {
|
||||||
|
readonly [Symbol.species]: PromiseConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegExp {
|
||||||
|
/**
|
||||||
|
* Matches a string with this regular expression, and returns an array containing the results of
|
||||||
|
* that search.
|
||||||
|
* @param string A string to search within.
|
||||||
|
*/
|
||||||
|
[Symbol.match](string: string): RegExpMatchArray | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces text in a string, using this regular expression.
|
||||||
|
* @param string A String object or string literal whose contents matching against
|
||||||
|
* this regular expression will be replaced
|
||||||
|
* @param replaceValue A String object or string literal containing the text to replace for every
|
||||||
|
* successful match of this regular expression.
|
||||||
|
*/
|
||||||
|
[Symbol.replace](string: string, replaceValue: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces text in a string, using this regular expression.
|
||||||
|
* @param string A String object or string literal whose contents matching against
|
||||||
|
* this regular expression will be replaced
|
||||||
|
* @param replacer A function that returns the replacement text.
|
||||||
|
*/
|
||||||
|
[Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the position beginning first substring match in a regular expression search
|
||||||
|
* using this regular expression.
|
||||||
|
*
|
||||||
|
* @param string The string to search within.
|
||||||
|
*/
|
||||||
|
[Symbol.search](string: string): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of substrings that were delimited by strings in the original input that
|
||||||
|
* match against this regular expression.
|
||||||
|
*
|
||||||
|
* If the regular expression contains capturing parentheses, then each time this
|
||||||
|
* regular expression matches, the results (including any undefined results) of the
|
||||||
|
* capturing parentheses are spliced.
|
||||||
|
*
|
||||||
|
* @param string string value to split
|
||||||
|
* @param limit if not undefined, the output array is truncated so that it contains no more
|
||||||
|
* than 'limit' elements.
|
||||||
|
*/
|
||||||
|
[Symbol.split](string: string, limit?: number): string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegExpConstructor {
|
||||||
|
readonly [Symbol.species]: RegExpConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface String {
|
||||||
|
/**
|
||||||
|
* Matches a string or an object that supports being matched against, and returns an array
|
||||||
|
* containing the results of that search, or null if no matches are found.
|
||||||
|
* @param matcher An object that supports being matched against.
|
||||||
|
*/
|
||||||
|
match(matcher: { [Symbol.match](string: string): RegExpMatchArray | null; }): RegExpMatchArray | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Passes a string and {@linkcode replaceValue} to the `[Symbol.replace]` method on {@linkcode searchValue}. This method is expected to implement its own replacement algorithm.
|
||||||
|
* @param searchValue An object that supports searching for and replacing matches within a string.
|
||||||
|
* @param replaceValue The replacement text.
|
||||||
|
*/
|
||||||
|
replace(searchValue: { [Symbol.replace](string: string, replaceValue: string): string; }, replaceValue: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces text in a string, using an object that supports replacement within a string.
|
||||||
|
* @param searchValue A object can search for and replace matches within a string.
|
||||||
|
* @param replacer A function that returns the replacement text.
|
||||||
|
*/
|
||||||
|
replace(searchValue: { [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; }, replacer: (substring: string, ...args: any[]) => string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the first substring match in a regular expression search.
|
||||||
|
* @param searcher An object which supports searching within a string.
|
||||||
|
*/
|
||||||
|
search(searcher: { [Symbol.search](string: string): number; }): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split a string into substrings using the specified separator and return them as an array.
|
||||||
|
* @param splitter An object that can split a string.
|
||||||
|
* @param limit A value used to limit the number of elements returned in the array.
|
||||||
|
*/
|
||||||
|
split(splitter: { [Symbol.split](string: string, limit?: number): string[]; }, limit?: number): string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArrayBuffer {
|
||||||
|
readonly [Symbol.toStringTag]: "ArrayBuffer";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataView<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Int8Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Uint8Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8ClampedArray<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Uint8ClampedArray";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Int16Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Uint16Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Int32Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Uint32Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Float32Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float64Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
readonly [Symbol.toStringTag]: "Float64Array";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArrayConstructor {
|
||||||
|
readonly [Symbol.species]: ArrayConstructor;
|
||||||
|
}
|
||||||
|
interface MapConstructor {
|
||||||
|
readonly [Symbol.species]: MapConstructor;
|
||||||
|
}
|
||||||
|
interface SetConstructor {
|
||||||
|
readonly [Symbol.species]: SetConstructor;
|
||||||
|
}
|
||||||
|
interface ArrayBufferConstructor {
|
||||||
|
readonly [Symbol.species]: ArrayBufferConstructor;
|
||||||
|
}
|
||||||
114
tools/tsgo/internal/bundled/libs/lib.es2016.array.include.d.ts
vendored
Normal file
114
tools/tsgo/internal/bundled/libs/lib.es2016.array.include.d.ts
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface Array<T> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: T, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadonlyArray<T> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: T, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint8ClampedArray<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint16Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Int32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Uint32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float32Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Float64Array<TArrayBuffer extends ArrayBufferLike> {
|
||||||
|
/**
|
||||||
|
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||||
|
* @param searchElement The element to search for.
|
||||||
|
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||||
|
*/
|
||||||
|
includes(searchElement: number, fromIndex?: number): boolean;
|
||||||
|
}
|
||||||
19
tools/tsgo/internal/bundled/libs/lib.es2016.d.ts
vendored
Normal file
19
tools/tsgo/internal/bundled/libs/lib.es2016.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2015" />
|
||||||
|
/// <reference lib="es2016.array.include" />
|
||||||
|
/// <reference lib="es2016.intl" />
|
||||||
21
tools/tsgo/internal/bundled/libs/lib.es2016.full.d.ts
vendored
Normal file
21
tools/tsgo/internal/bundled/libs/lib.es2016.full.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2016" />
|
||||||
|
/// <reference lib="dom" />
|
||||||
|
/// <reference lib="webworker.importscripts" />
|
||||||
|
/// <reference lib="scripthost" />
|
||||||
|
/// <reference lib="dom.iterable" />
|
||||||
29
tools/tsgo/internal/bundled/libs/lib.es2016.intl.d.ts
vendored
Normal file
29
tools/tsgo/internal/bundled/libs/lib.es2016.intl.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
declare namespace Intl {
|
||||||
|
/**
|
||||||
|
* The `Intl.getCanonicalLocales()` method returns an array containing
|
||||||
|
* the canonical locale names. Duplicates will be omitted and elements
|
||||||
|
* will be validated as structurally valid language tags.
|
||||||
|
*
|
||||||
|
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/getCanonicalLocales)
|
||||||
|
*
|
||||||
|
* @param locale A list of String values for which to get the canonical locale names
|
||||||
|
* @returns An array containing the canonical and validated locale names.
|
||||||
|
*/
|
||||||
|
function getCanonicalLocales(locale?: string | readonly string[]): string[];
|
||||||
|
}
|
||||||
19
tools/tsgo/internal/bundled/libs/lib.es2017.arraybuffer.d.ts
vendored
Normal file
19
tools/tsgo/internal/bundled/libs/lib.es2017.arraybuffer.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface ArrayBufferConstructor {
|
||||||
|
new (): ArrayBuffer;
|
||||||
|
}
|
||||||
24
tools/tsgo/internal/bundled/libs/lib.es2017.d.ts
vendored
Normal file
24
tools/tsgo/internal/bundled/libs/lib.es2017.d.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2016" />
|
||||||
|
/// <reference lib="es2017.arraybuffer" />
|
||||||
|
/// <reference lib="es2017.date" />
|
||||||
|
/// <reference lib="es2017.intl" />
|
||||||
|
/// <reference lib="es2017.object" />
|
||||||
|
/// <reference lib="es2017.sharedmemory" />
|
||||||
|
/// <reference lib="es2017.string" />
|
||||||
|
/// <reference lib="es2017.typedarrays" />
|
||||||
29
tools/tsgo/internal/bundled/libs/lib.es2017.date.d.ts
vendored
Normal file
29
tools/tsgo/internal/bundled/libs/lib.es2017.date.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
interface DateConstructor {
|
||||||
|
/**
|
||||||
|
* Returns the number of milliseconds between midnight, January 1, 1970 Universal Coordinated Time (UTC) (or GMT) and the specified date.
|
||||||
|
* @param year The full year designation is required for cross-century date accuracy. If year is between 0 and 99 is used, then year is assumed to be 1900 + year.
|
||||||
|
* @param monthIndex The month as a number between 0 and 11 (January to December).
|
||||||
|
* @param date The date as a number between 1 and 31.
|
||||||
|
* @param hours Must be supplied if minutes is supplied. A number from 0 to 23 (midnight to 11pm) that specifies the hour.
|
||||||
|
* @param minutes Must be supplied if seconds is supplied. A number from 0 to 59 that specifies the minutes.
|
||||||
|
* @param seconds Must be supplied if milliseconds is supplied. A number from 0 to 59 that specifies the seconds.
|
||||||
|
* @param ms A number from 0 to 999 that specifies the milliseconds.
|
||||||
|
*/
|
||||||
|
UTC(year: number, monthIndex?: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number;
|
||||||
|
}
|
||||||
21
tools/tsgo/internal/bundled/libs/lib.es2017.full.d.ts
vendored
Normal file
21
tools/tsgo/internal/bundled/libs/lib.es2017.full.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/// <reference lib="es2017" />
|
||||||
|
/// <reference lib="dom" />
|
||||||
|
/// <reference lib="webworker.importscripts" />
|
||||||
|
/// <reference lib="scripthost" />
|
||||||
|
/// <reference lib="dom.iterable" />
|
||||||
42
tools/tsgo/internal/bundled/libs/lib.es2017.intl.d.ts
vendored
Normal file
42
tools/tsgo/internal/bundled/libs/lib.es2017.intl.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||||
|
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||||
|
|
||||||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||||||
|
and limitations under the License.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
declare namespace Intl {
|
||||||
|
interface DateTimeFormatPartTypesRegistry {
|
||||||
|
day: any;
|
||||||
|
dayPeriod: any;
|
||||||
|
era: any;
|
||||||
|
hour: any;
|
||||||
|
literal: any;
|
||||||
|
minute: any;
|
||||||
|
month: any;
|
||||||
|
second: any;
|
||||||
|
timeZoneName: any;
|
||||||
|
weekday: any;
|
||||||
|
year: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
type DateTimeFormatPartTypes = keyof DateTimeFormatPartTypesRegistry;
|
||||||
|
|
||||||
|
interface DateTimeFormatPart {
|
||||||
|
type: DateTimeFormatPartTypes;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DateTimeFormat {
|
||||||
|
formatToParts(date?: Date | number): DateTimeFormatPart[];
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user