Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .dprint.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
// Note: if adding new languages, make sure settings.template.json is updated too.
// Also, if updating typescript, update the one in package.json.
"plugins": [
"https://plugins.dprint.dev/typescript-0.95.5.wasm",
"https://plugins.dprint.dev/typescript-0.95.7.wasm",
"https://plugins.dprint.dev/json-0.20.0.wasm",
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm",
"https://plugins.dprint.dev/exec-0.5.1.json@492414e39dea4dccc07b4af796d2f4efdb89e84bae2bd4e1e924c0cc050855bf"
Expand Down
2 changes: 1 addition & 1 deletion NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

---------------------------------------------------------

golang.org/x/sync v0.14.0 - BSD-3-Clause
golang.org/x/sync v0.15.0 - BSD-3-Clause

Copyright 2009 The Go Authors.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Preview

A preview build is available on npm as `@typescript/native-preview`.
A preview build is available on npm as [`@typescript/native-preview`](https://www.npmjs.com/package/@typescript/native-preview).

```sh
npm install @typescript/native-preview
Expand Down
8 changes: 4 additions & 4 deletions _tools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module github.com/microsoft/typescript-go/_tools
go 1.24.0

require (
github.com/golangci/plugin-module-register v0.1.2-0.20250519122030-95854f10c778
golang.org/x/mod v0.24.0
golang.org/x/tools v0.33.0
github.com/golangci/plugin-module-register v0.1.2
golang.org/x/mod v0.25.0
golang.org/x/tools v0.34.0
gotest.tools/v3 v3.5.2
)

require (
github.com/google/go-cmp v0.6.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sync v0.15.0 // indirect
)
16 changes: 8 additions & 8 deletions _tools/go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
github.com/golangci/plugin-module-register v0.1.2-0.20250519122030-95854f10c778 h1:a5T2fJwhfuTPuhCau4IPP4ZGGndS/ysLzDorg1mA2P4=
github.com/golangci/plugin-module-register v0.1.2-0.20250519122030-95854f10c778/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw=
github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg=
github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8
github.com/google/go-cmp v0.7.0
github.com/peter-evans/patience v0.3.0
golang.org/x/sync v0.14.0
golang.org/x/sync v0.15.0
golang.org/x/sys v0.33.0
gotest.tools/v3 v3.5.2
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
Expand Down
22 changes: 11 additions & 11 deletions internal/api/encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ import (
"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/scanner"
"github.com/microsoft/typescript-go/internal/testutil/baseline"
"gotest.tools/v3/assert"
)

var parseCompilerOptions = &core.SourceFileAffectingCompilerOptions{
var parseCompilerOptions = core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetLatest,
}

func TestEncodeSourceFile(t *testing.T) {
t.Parallel()
sourceFile := parser.ParseSourceFile("/test.ts", "/test.ts", "import { bar } from \"bar\";\nexport function foo<T, U>(a: string, b: string): any {}\nfoo();", parseCompilerOptions, nil, scanner.JSDocParsingModeParseAll)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/test.ts",
Path: "/test.ts",
CompilerOptions: parseCompilerOptions,
}, "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, "")
Expand All @@ -42,14 +45,11 @@ func BenchmarkEncodeSourceFile(b *testing.B) {
filePath := filepath.Join(repo.TypeScriptSubmodulePath, "src/compiler/checker.ts")
fileContent, err := os.ReadFile(filePath)
assert.NilError(b, err)
sourceFile := parser.ParseSourceFile(
"/checker.ts",
"/checker.ts",
string(fileContent),
parseCompilerOptions,
nil,
scanner.JSDocParsingModeParseAll,
)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/checker.ts",
Path: "/checker.ts",
CompilerOptions: parseCompilerOptions,
}, string(fileContent), core.ScriptKindTS)

for b.Loop() {
_, err := encoder.EncodeSourceFile(sourceFile, "")
Expand Down
40 changes: 21 additions & 19 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -9985,17 +9985,14 @@ type SourceFile struct {
compositeNodeBase

// Fields set by NewSourceFile

text string
fileName string
path tspath.Path
Statements *NodeList // NodeList[*Statement]
fileName string // For debugging convenience
parseOptions SourceFileParseOptions
text string
Statements *NodeList // NodeList[*Statement]

// Fields set by parser

diagnostics []*Diagnostic
jsdocDiagnostics []*Diagnostic
LanguageVersion core.ScriptTarget
LanguageVariant core.LanguageVariant
ScriptKind core.ScriptKind
IsDeclarationFile bool
Expand Down Expand Up @@ -10040,30 +10037,36 @@ type SourceFile struct {
tokenCache map[core.TextRange]*Node
}

func (f *NodeFactory) NewSourceFile(text string, fileName string, path tspath.Path, statements *NodeList) *Node {
if (tspath.GetEncodedRootLength(fileName) == 0 && !strings.HasPrefix(fileName, "^/")) || fileName != tspath.NormalizePath(fileName) {
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", fileName))
func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, statements *NodeList) *Node {
if (tspath.GetEncodedRootLength(opts.FileName) == 0 && !strings.HasPrefix(opts.FileName, "^/")) || opts.FileName != tspath.NormalizePath(opts.FileName) {
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", opts.FileName))
}

data := &SourceFile{}
data.fileName = opts.FileName
data.parseOptions = opts
data.text = text
data.fileName = fileName
data.path = path
data.Statements = statements
data.LanguageVersion = core.ScriptTargetLatest
return f.newNode(KindSourceFile, data)
}

func (node *SourceFile) ParseOptions() SourceFileParseOptions {
return node.parseOptions
}

func (node *SourceFile) LanguageVersion() core.ScriptTarget {
return node.parseOptions.CompilerOptions.EmitScriptTarget
}

func (node *SourceFile) Text() string {
return node.text
}

func (node *SourceFile) FileName() string {
return node.fileName
return node.parseOptions.FileName
}

func (node *SourceFile) Path() tspath.Path {
return node.path
return node.parseOptions.Path
}

func (node *SourceFile) OriginalFileName() string {
Expand Down Expand Up @@ -10120,7 +10123,6 @@ func (node *SourceFile) IsJS() bool {

func (node *SourceFile) copyFrom(other *SourceFile) {
// Do not copy fields set by NewSourceFile (Text, FileName, Path, or Statements)
node.LanguageVersion = other.LanguageVersion
node.LanguageVariant = other.LanguageVariant
node.ScriptKind = other.ScriptKind
node.IsDeclarationFile = other.IsDeclarationFile
Expand All @@ -10141,7 +10143,7 @@ func (node *SourceFile) copyFrom(other *SourceFile) {
}

func (node *SourceFile) Clone(f NodeFactoryCoercible) *Node {
updated := f.AsNodeFactory().NewSourceFile(node.Text(), node.FileName(), node.Path(), node.Statements)
updated := f.AsNodeFactory().NewSourceFile(node.parseOptions, node.text, node.Statements)
newFile := updated.AsSourceFile()
newFile.copyFrom(node)
return cloneNode(updated, node.AsNode(), f.AsNodeFactory().hooks)
Expand All @@ -10153,7 +10155,7 @@ func (node *SourceFile) computeSubtreeFacts() SubtreeFacts {

func (f *NodeFactory) UpdateSourceFile(node *SourceFile, statements *StatementList) *Node {
if statements != node.Statements {
updated := f.NewSourceFile(node.Text(), node.fileName, node.path, statements).AsSourceFile()
updated := f.NewSourceFile(node.parseOptions, node.text, statements).AsSourceFile()
updated.copyFrom(node)
return updateNode(updated.AsNode(), node.AsNode(), f.hooks)
}
Expand Down
168 changes: 168 additions & 0 deletions internal/ast/parseoptions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package ast

import (
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/tspath"
)

type JSDocParsingMode int

const (
JSDocParsingModeParseAll JSDocParsingMode = iota
JSDocParsingModeParseNone
JSDocParsingModeParseForTypeErrors
JSDocParsingModeParseForTypeInfo
)

type SourceFileParseOptions struct {
FileName string
Path tspath.Path
CompilerOptions core.SourceFileAffectingCompilerOptions
ExternalModuleIndicatorOptions ExternalModuleIndicatorOptions
JSDocParsingMode JSDocParsingMode
}

func GetSourceFileAffectingCompilerOptions(fileName string, options *core.CompilerOptions) core.SourceFileAffectingCompilerOptions {
// Declaration files are not parsed/bound differently depending on compiler options.
if tspath.IsDeclarationFileName(fileName) {
return core.SourceFileAffectingCompilerOptions{}
}
return options.SourceFileAffecting()
}

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 IsJsxOpeningElement(node) || IsJsxFragment(node) {
found = node
return true
}
return node.ForEachChild(visitor)
}
visitor(node)

return found
}
Loading
Loading