vendor tsgo
This commit is contained in:
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
|
||||
}
|
||||
Reference in New Issue
Block a user