621 lines
19 KiB
Go
621 lines
19 KiB
Go
package tsoptions
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
)
|
|
|
|
func parseTristate(value any) core.Tristate {
|
|
if value == nil {
|
|
return core.TSUnknown
|
|
}
|
|
if v, ok := value.(core.Tristate); ok {
|
|
return v
|
|
}
|
|
if value == true {
|
|
return core.TSTrue
|
|
} else {
|
|
return core.TSFalse
|
|
}
|
|
}
|
|
|
|
func parseStringArray(value any) []string {
|
|
if arr, ok := value.([]any); ok {
|
|
if arr == nil {
|
|
return nil
|
|
}
|
|
result := make([]string, 0, len(arr))
|
|
for _, v := range arr {
|
|
if str, ok := v.(string); ok {
|
|
result = append(result, str)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseStringMap(value any) *collections.OrderedMap[string, []string] {
|
|
if m, ok := value.(*collections.OrderedMap[string, any]); ok {
|
|
result := collections.NewOrderedMapWithSizeHint[string, []string](m.Size())
|
|
for k, v := range m.Entries() {
|
|
result.Set(k, parseStringArray(v))
|
|
}
|
|
return result
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseString(value any) string {
|
|
if str, ok := value.(string); ok {
|
|
return str
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func parseNumber(value any) *int {
|
|
if num, ok := value.(int); ok {
|
|
return &num
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseProjectReference(json any) []*core.ProjectReference {
|
|
var result []*core.ProjectReference
|
|
if v, ok := json.(*collections.OrderedMap[string, any]); ok {
|
|
var reference core.ProjectReference
|
|
if v, ok := v.Get("path"); ok {
|
|
reference.Path = v.(string)
|
|
}
|
|
if v, ok := v.Get("circular"); ok {
|
|
reference.Circular = v.(bool)
|
|
}
|
|
result = append(result, &reference)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func parseJsonToStringKey(json any) *collections.OrderedMap[string, any] {
|
|
result := collections.NewOrderedMapWithSizeHint[string, any](6)
|
|
if m, ok := json.(*collections.OrderedMap[string, any]); ok {
|
|
if v, ok := m.Get("include"); ok {
|
|
result.Set("include", v)
|
|
}
|
|
if v, ok := m.Get("exclude"); ok {
|
|
result.Set("exclude", v)
|
|
}
|
|
if v, ok := m.Get("files"); ok {
|
|
result.Set("files", v)
|
|
}
|
|
if v, ok := m.Get("references"); ok {
|
|
result.Set("references", v)
|
|
}
|
|
if v, ok := m.Get("extends"); ok {
|
|
if str, ok := v.(string); ok {
|
|
result.Set("extends", []any{str})
|
|
}
|
|
result.Set("extends", v)
|
|
}
|
|
if v, ok := m.Get("compilerOptions"); ok {
|
|
result.Set("compilerOptions", v)
|
|
}
|
|
if v, ok := m.Get("excludes"); ok {
|
|
result.Set("excludes", v)
|
|
}
|
|
if v, ok := m.Get("typeAcquisition"); ok {
|
|
result.Set("typeAcquisition", v)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
type optionParser interface {
|
|
ParseOption(key string, value any) []*ast.Diagnostic
|
|
UnknownOptionDiagnostic() *diagnostics.Message
|
|
}
|
|
|
|
type compilerOptionsParser struct {
|
|
*core.CompilerOptions
|
|
}
|
|
|
|
func (o *compilerOptionsParser) ParseOption(key string, value any) []*ast.Diagnostic {
|
|
return ParseCompilerOptions(key, value, o.CompilerOptions)
|
|
}
|
|
|
|
func (o *compilerOptionsParser) UnknownOptionDiagnostic() *diagnostics.Message {
|
|
return extraKeyDiagnostics("compilerOptions")
|
|
}
|
|
|
|
type watchOptionsParser struct {
|
|
*core.WatchOptions
|
|
}
|
|
|
|
func (o *watchOptionsParser) ParseOption(key string, value any) []*ast.Diagnostic {
|
|
return ParseWatchOptions(key, value, o.WatchOptions)
|
|
}
|
|
|
|
func (o *watchOptionsParser) UnknownOptionDiagnostic() *diagnostics.Message {
|
|
return extraKeyDiagnostics("watchOptions")
|
|
}
|
|
|
|
type typeAcquisitionParser struct {
|
|
*core.TypeAcquisition
|
|
}
|
|
|
|
func (o *typeAcquisitionParser) ParseOption(key string, value any) []*ast.Diagnostic {
|
|
return ParseTypeAcquisition(key, value, o.TypeAcquisition)
|
|
}
|
|
|
|
func (o *typeAcquisitionParser) UnknownOptionDiagnostic() *diagnostics.Message {
|
|
return extraKeyDiagnostics("typeAcquisition")
|
|
}
|
|
|
|
type buildOptionsParser struct {
|
|
*core.BuildOptions
|
|
}
|
|
|
|
func (o *buildOptionsParser) ParseOption(key string, value any) []*ast.Diagnostic {
|
|
return ParseBuildOptions(key, value, o.BuildOptions)
|
|
}
|
|
|
|
func (o *buildOptionsParser) UnknownOptionDiagnostic() *diagnostics.Message {
|
|
return extraKeyDiagnostics("buildOptions")
|
|
}
|
|
|
|
func ParseCompilerOptions(key string, value any, allOptions *core.CompilerOptions) []*ast.Diagnostic {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
if allOptions == nil {
|
|
return nil
|
|
}
|
|
parseCompilerOptions(key, value, allOptions)
|
|
return nil
|
|
}
|
|
|
|
func parseCompilerOptions(key string, value any, allOptions *core.CompilerOptions) (foundKey bool) {
|
|
option := CommandLineCompilerOptionsMap.Get(key)
|
|
if option != nil {
|
|
key = option.Name
|
|
}
|
|
switch key {
|
|
case "allowJs":
|
|
allOptions.AllowJs = parseTristate(value)
|
|
case "allowImportingTsExtensions":
|
|
allOptions.AllowImportingTsExtensions = parseTristate(value)
|
|
case "allowSyntheticDefaultImports":
|
|
allOptions.AllowSyntheticDefaultImports = parseTristate(value)
|
|
case "allowNonTsExtensions":
|
|
allOptions.AllowNonTsExtensions = parseTristate(value)
|
|
case "allowUmdGlobalAccess":
|
|
allOptions.AllowUmdGlobalAccess = parseTristate(value)
|
|
case "allowUnreachableCode":
|
|
allOptions.AllowUnreachableCode = parseTristate(value)
|
|
case "allowUnusedLabels":
|
|
allOptions.AllowUnusedLabels = parseTristate(value)
|
|
case "allowArbitraryExtensions":
|
|
allOptions.AllowArbitraryExtensions = parseTristate(value)
|
|
case "alwaysStrict":
|
|
allOptions.AlwaysStrict = parseTristate(value)
|
|
case "assumeChangesOnlyAffectDirectDependencies":
|
|
allOptions.AssumeChangesOnlyAffectDirectDependencies = parseTristate(value)
|
|
case "baseUrl":
|
|
allOptions.BaseUrl = parseString(value)
|
|
case "build":
|
|
allOptions.Build = parseTristate(value)
|
|
case "checkJs":
|
|
allOptions.CheckJs = parseTristate(value)
|
|
case "customConditions":
|
|
allOptions.CustomConditions = parseStringArray(value)
|
|
case "composite":
|
|
allOptions.Composite = parseTristate(value)
|
|
case "declarationDir":
|
|
allOptions.DeclarationDir = parseString(value)
|
|
case "diagnostics":
|
|
allOptions.Diagnostics = parseTristate(value)
|
|
case "disableSizeLimit":
|
|
allOptions.DisableSizeLimit = parseTristate(value)
|
|
case "disableSourceOfProjectReferenceRedirect":
|
|
allOptions.DisableSourceOfProjectReferenceRedirect = parseTristate(value)
|
|
case "disableSolutionSearching":
|
|
allOptions.DisableSolutionSearching = parseTristate(value)
|
|
case "disableReferencedProjectLoad":
|
|
allOptions.DisableReferencedProjectLoad = parseTristate(value)
|
|
case "declarationMap":
|
|
allOptions.DeclarationMap = parseTristate(value)
|
|
case "declaration":
|
|
allOptions.Declaration = parseTristate(value)
|
|
case "downlevelIteration":
|
|
allOptions.DownlevelIteration = parseTristate(value)
|
|
case "erasableSyntaxOnly":
|
|
allOptions.ErasableSyntaxOnly = parseTristate(value)
|
|
case "emitDeclarationOnly":
|
|
allOptions.EmitDeclarationOnly = parseTristate(value)
|
|
case "extendedDiagnostics":
|
|
allOptions.ExtendedDiagnostics = parseTristate(value)
|
|
case "emitDecoratorMetadata":
|
|
allOptions.EmitDecoratorMetadata = parseTristate(value)
|
|
case "emitBOM":
|
|
allOptions.EmitBOM = parseTristate(value)
|
|
case "esModuleInterop":
|
|
allOptions.ESModuleInterop = parseTristate(value)
|
|
case "exactOptionalPropertyTypes":
|
|
allOptions.ExactOptionalPropertyTypes = parseTristate(value)
|
|
case "explainFiles":
|
|
allOptions.ExplainFiles = parseTristate(value)
|
|
case "experimentalDecorators":
|
|
allOptions.ExperimentalDecorators = parseTristate(value)
|
|
case "forceConsistentCasingInFileNames":
|
|
allOptions.ForceConsistentCasingInFileNames = parseTristate(value)
|
|
case "generateCpuProfile":
|
|
allOptions.GenerateCpuProfile = parseString(value)
|
|
case "generateTrace":
|
|
allOptions.GenerateTrace = parseString(value)
|
|
case "isolatedModules":
|
|
allOptions.IsolatedModules = parseTristate(value)
|
|
case "ignoreDeprecations":
|
|
allOptions.IgnoreDeprecations = parseString(value)
|
|
case "importHelpers":
|
|
allOptions.ImportHelpers = parseTristate(value)
|
|
case "incremental":
|
|
allOptions.Incremental = parseTristate(value)
|
|
case "init":
|
|
allOptions.Init = parseTristate(value)
|
|
case "inlineSourceMap":
|
|
allOptions.InlineSourceMap = parseTristate(value)
|
|
case "inlineSources":
|
|
allOptions.InlineSources = parseTristate(value)
|
|
case "isolatedDeclarations":
|
|
allOptions.IsolatedDeclarations = parseTristate(value)
|
|
case "jsx":
|
|
allOptions.Jsx = floatOrInt32ToFlag[core.JsxEmit](value)
|
|
case "jsxFactory":
|
|
allOptions.JsxFactory = parseString(value)
|
|
case "jsxFragmentFactory":
|
|
allOptions.JsxFragmentFactory = parseString(value)
|
|
case "jsxImportSource":
|
|
allOptions.JsxImportSource = parseString(value)
|
|
case "lib":
|
|
if _, ok := value.([]string); ok {
|
|
allOptions.Lib = value.([]string)
|
|
} else {
|
|
allOptions.Lib = parseStringArray(value)
|
|
}
|
|
case "libReplacement":
|
|
allOptions.LibReplacement = parseTristate(value)
|
|
case "listEmittedFiles":
|
|
allOptions.ListEmittedFiles = parseTristate(value)
|
|
case "listFiles":
|
|
allOptions.ListFiles = parseTristate(value)
|
|
case "listFilesOnly":
|
|
allOptions.ListFilesOnly = parseTristate(value)
|
|
case "locale":
|
|
allOptions.Locale = parseString(value)
|
|
case "mapRoot":
|
|
allOptions.MapRoot = parseString(value)
|
|
case "module":
|
|
allOptions.Module = floatOrInt32ToFlag[core.ModuleKind](value)
|
|
case "moduleDetectionKind":
|
|
allOptions.ModuleDetection = floatOrInt32ToFlag[core.ModuleDetectionKind](value)
|
|
case "moduleResolution":
|
|
allOptions.ModuleResolution = floatOrInt32ToFlag[core.ModuleResolutionKind](value)
|
|
case "moduleSuffixes":
|
|
allOptions.ModuleSuffixes = parseStringArray(value)
|
|
case "moduleDetection":
|
|
allOptions.ModuleDetection = floatOrInt32ToFlag[core.ModuleDetectionKind](value)
|
|
case "noCheck":
|
|
allOptions.NoCheck = parseTristate(value)
|
|
case "noFallthroughCasesInSwitch":
|
|
allOptions.NoFallthroughCasesInSwitch = parseTristate(value)
|
|
case "noEmitForJsFiles":
|
|
allOptions.NoEmitForJsFiles = parseTristate(value)
|
|
case "noErrorTruncation":
|
|
allOptions.NoErrorTruncation = parseTristate(value)
|
|
case "noImplicitAny":
|
|
allOptions.NoImplicitAny = parseTristate(value)
|
|
case "noImplicitThis":
|
|
allOptions.NoImplicitThis = parseTristate(value)
|
|
case "noLib":
|
|
allOptions.NoLib = parseTristate(value)
|
|
case "noPropertyAccessFromIndexSignature":
|
|
allOptions.NoPropertyAccessFromIndexSignature = parseTristate(value)
|
|
case "noUncheckedIndexedAccess":
|
|
allOptions.NoUncheckedIndexedAccess = parseTristate(value)
|
|
case "noEmitHelpers":
|
|
allOptions.NoEmitHelpers = parseTristate(value)
|
|
case "noEmitOnError":
|
|
allOptions.NoEmitOnError = parseTristate(value)
|
|
case "noImplicitReturns":
|
|
allOptions.NoImplicitReturns = parseTristate(value)
|
|
case "noUnusedLocals":
|
|
allOptions.NoUnusedLocals = parseTristate(value)
|
|
case "noUnusedParameters":
|
|
allOptions.NoUnusedParameters = parseTristate(value)
|
|
case "noImplicitOverride":
|
|
allOptions.NoImplicitOverride = parseTristate(value)
|
|
case "noUncheckedSideEffectImports":
|
|
allOptions.NoUncheckedSideEffectImports = parseTristate(value)
|
|
case "outFile":
|
|
allOptions.OutFile = parseString(value)
|
|
case "noResolve":
|
|
allOptions.NoResolve = parseTristate(value)
|
|
case "paths":
|
|
allOptions.Paths = parseStringMap(value)
|
|
case "preserveWatchOutput":
|
|
allOptions.PreserveWatchOutput = parseTristate(value)
|
|
case "preserveConstEnums":
|
|
allOptions.PreserveConstEnums = parseTristate(value)
|
|
case "preserveSymlinks":
|
|
allOptions.PreserveSymlinks = parseTristate(value)
|
|
case "project":
|
|
allOptions.Project = parseString(value)
|
|
case "pretty":
|
|
allOptions.Pretty = parseTristate(value)
|
|
case "resolveJsonModule":
|
|
allOptions.ResolveJsonModule = parseTristate(value)
|
|
case "resolvePackageJsonExports":
|
|
allOptions.ResolvePackageJsonExports = parseTristate(value)
|
|
case "resolvePackageJsonImports":
|
|
allOptions.ResolvePackageJsonImports = parseTristate(value)
|
|
case "reactNamespace":
|
|
allOptions.ReactNamespace = parseString(value)
|
|
case "rewriteRelativeImportExtensions":
|
|
allOptions.RewriteRelativeImportExtensions = parseTristate(value)
|
|
case "rootDir":
|
|
allOptions.RootDir = parseString(value)
|
|
case "rootDirs":
|
|
allOptions.RootDirs = parseStringArray(value)
|
|
case "removeComments":
|
|
allOptions.RemoveComments = parseTristate(value)
|
|
case "strict":
|
|
allOptions.Strict = parseTristate(value)
|
|
case "strictBindCallApply":
|
|
allOptions.StrictBindCallApply = parseTristate(value)
|
|
case "strictBuiltinIteratorReturn":
|
|
allOptions.StrictBuiltinIteratorReturn = parseTristate(value)
|
|
case "strictFunctionTypes":
|
|
allOptions.StrictFunctionTypes = parseTristate(value)
|
|
case "strictNullChecks":
|
|
allOptions.StrictNullChecks = parseTristate(value)
|
|
case "strictPropertyInitialization":
|
|
allOptions.StrictPropertyInitialization = parseTristate(value)
|
|
case "skipDefaultLibCheck":
|
|
allOptions.SkipDefaultLibCheck = parseTristate(value)
|
|
case "sourceMap":
|
|
allOptions.SourceMap = parseTristate(value)
|
|
case "sourceRoot":
|
|
allOptions.SourceRoot = parseString(value)
|
|
case "stripInternal":
|
|
allOptions.StripInternal = parseTristate(value)
|
|
case "suppressOutputPathCheck":
|
|
allOptions.SuppressOutputPathCheck = parseTristate(value)
|
|
case "target":
|
|
allOptions.Target = floatOrInt32ToFlag[core.ScriptTarget](value)
|
|
case "traceResolution":
|
|
allOptions.TraceResolution = parseTristate(value)
|
|
case "tsBuildInfoFile":
|
|
allOptions.TsBuildInfoFile = parseString(value)
|
|
case "typeRoots":
|
|
allOptions.TypeRoots = parseStringArray(value)
|
|
case "types":
|
|
allOptions.Types = parseStringArray(value)
|
|
case "useDefineForClassFields":
|
|
allOptions.UseDefineForClassFields = parseTristate(value)
|
|
case "useUnknownInCatchVariables":
|
|
allOptions.UseUnknownInCatchVariables = parseTristate(value)
|
|
case "verbatimModuleSyntax":
|
|
allOptions.VerbatimModuleSyntax = parseTristate(value)
|
|
case "version":
|
|
allOptions.Version = parseTristate(value)
|
|
case "help":
|
|
allOptions.Help = parseTristate(value)
|
|
case "all":
|
|
allOptions.All = parseTristate(value)
|
|
case "maxNodeModuleJsDepth":
|
|
allOptions.MaxNodeModuleJsDepth = parseNumber(value)
|
|
case "skipLibCheck":
|
|
allOptions.SkipLibCheck = parseTristate(value)
|
|
case "noEmit":
|
|
allOptions.NoEmit = parseTristate(value)
|
|
case "showConfig":
|
|
allOptions.ShowConfig = parseTristate(value)
|
|
case "configFilePath":
|
|
allOptions.ConfigFilePath = parseString(value)
|
|
case "noDtsResolution":
|
|
allOptions.NoDtsResolution = parseTristate(value)
|
|
case "pathsBasePath":
|
|
allOptions.PathsBasePath = parseString(value)
|
|
case "outDir":
|
|
allOptions.OutDir = parseString(value)
|
|
case "newLine":
|
|
allOptions.NewLine = floatOrInt32ToFlag[core.NewLineKind](value)
|
|
case "watch":
|
|
allOptions.Watch = parseTristate(value)
|
|
case "pprofDir":
|
|
allOptions.PprofDir = parseString(value)
|
|
case "singleThreaded":
|
|
allOptions.SingleThreaded = parseTristate(value)
|
|
case "quiet":
|
|
allOptions.Quiet = parseTristate(value)
|
|
default:
|
|
// different than any key above
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func floatOrInt32ToFlag[T ~int32](value any) T {
|
|
if v, ok := value.(T); ok {
|
|
return v
|
|
}
|
|
return T(value.(float64))
|
|
}
|
|
|
|
func ParseWatchOptions(key string, value any, allOptions *core.WatchOptions) []*ast.Diagnostic {
|
|
if allOptions == nil {
|
|
return nil
|
|
}
|
|
switch key {
|
|
case "watchInterval":
|
|
allOptions.Interval = parseNumber(value)
|
|
case "watchFile":
|
|
if value != nil {
|
|
allOptions.FileKind = value.(core.WatchFileKind)
|
|
}
|
|
case "watchDirectory":
|
|
if value != nil {
|
|
allOptions.DirectoryKind = value.(core.WatchDirectoryKind)
|
|
}
|
|
case "fallbackPolling":
|
|
if value != nil {
|
|
allOptions.FallbackPolling = value.(core.PollingKind)
|
|
}
|
|
case "synchronousWatchDirectory":
|
|
allOptions.SyncWatchDir = parseTristate(value)
|
|
case "excludeDirectories":
|
|
allOptions.ExcludeDir = parseStringArray(value)
|
|
case "excludeFiles":
|
|
allOptions.ExcludeFiles = parseStringArray(value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ParseTypeAcquisition(key string, value any, allOptions *core.TypeAcquisition) []*ast.Diagnostic {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
if allOptions == nil {
|
|
return nil
|
|
}
|
|
switch key {
|
|
case "enable":
|
|
allOptions.Enable = parseTristate(value)
|
|
case "include":
|
|
allOptions.Include = parseStringArray(value)
|
|
case "exclude":
|
|
allOptions.Exclude = parseStringArray(value)
|
|
case "disableFilenameBasedTypeAcquisition":
|
|
allOptions.DisableFilenameBasedTypeAcquisition = parseTristate(value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ParseBuildOptions(key string, value any, allOptions *core.BuildOptions) []*ast.Diagnostic {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
if allOptions == nil {
|
|
return nil
|
|
}
|
|
option := BuildNameMap.Get(key)
|
|
if option != nil {
|
|
key = option.Name
|
|
}
|
|
switch key {
|
|
case "clean":
|
|
allOptions.Clean = parseTristate(value)
|
|
case "dry":
|
|
allOptions.Dry = parseTristate(value)
|
|
case "force":
|
|
allOptions.Force = parseTristate(value)
|
|
case "stopBuildOnErrors":
|
|
allOptions.StopBuildOnErrors = parseTristate(value)
|
|
case "verbose":
|
|
allOptions.Verbose = parseTristate(value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// mergeCompilerOptions merges the source compiler options into the target compiler options
|
|
// with optional awareness of explicitly set null values in the raw JSON.
|
|
// Fields in the source options will overwrite the corresponding fields in the target options,
|
|
// including when they are explicitly set to null in the raw configuration (if rawSource is provided).
|
|
func mergeCompilerOptions(targetOptions, sourceOptions *core.CompilerOptions, rawSource any) *core.CompilerOptions {
|
|
if sourceOptions == nil {
|
|
return targetOptions
|
|
}
|
|
|
|
// Collect explicitly null field names from raw JSON
|
|
var explicitNullFields collections.Set[string]
|
|
if rawSource != nil {
|
|
if rawMap, ok := rawSource.(*collections.OrderedMap[string, any]); ok {
|
|
if compilerOptionsRaw, exists := rawMap.Get("compilerOptions"); exists {
|
|
if compilerOptionsMap, ok := compilerOptionsRaw.(*collections.OrderedMap[string, any]); ok {
|
|
for key, value := range compilerOptionsMap.Entries() {
|
|
if value == nil {
|
|
explicitNullFields.Add(key)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do the merge, handling explicit nulls during the normal merge
|
|
targetValue := reflect.ValueOf(targetOptions).Elem()
|
|
sourceValue := reflect.ValueOf(sourceOptions).Elem()
|
|
targetType := targetValue.Type()
|
|
|
|
for i := range targetValue.NumField() {
|
|
targetField := targetValue.Field(i)
|
|
sourceField := sourceValue.Field(i)
|
|
|
|
// Get the JSON field name for this struct field and check if it's explicitly null
|
|
if jsonTag := targetType.Field(i).Tag.Get("json"); jsonTag != "" {
|
|
if jsonFieldName, _, _ := strings.Cut(jsonTag, ","); jsonFieldName != "" && explicitNullFields.Has(jsonFieldName) {
|
|
targetField.SetZero()
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Normal merge behavior: copy non-zero fields
|
|
if !sourceField.IsZero() {
|
|
targetField.Set(sourceField)
|
|
}
|
|
}
|
|
|
|
return targetOptions
|
|
}
|
|
|
|
func convertToOptionsWithAbsolutePaths(optionsBase *collections.OrderedMap[string, any], optionMap CommandLineOptionNameMap, cwd string) *collections.OrderedMap[string, any] {
|
|
// !!! convert to options with absolute paths was previously done with `CompilerOptions` object, but for ease of implementation, we do it pre-conversion.
|
|
// !!! Revisit this choice if/when refactoring when conversion is done in tsconfig parsing
|
|
if optionsBase == nil {
|
|
return nil
|
|
}
|
|
for o, v := range optionsBase.Entries() {
|
|
result, ok := ConvertOptionToAbsolutePath(o, v, optionMap, cwd)
|
|
if ok {
|
|
optionsBase.Set(o, result)
|
|
}
|
|
}
|
|
return optionsBase
|
|
}
|
|
|
|
func ConvertOptionToAbsolutePath(o string, v any, optionMap CommandLineOptionNameMap, cwd string) (any, bool) {
|
|
option := optionMap.Get(o)
|
|
if option == nil {
|
|
return nil, false
|
|
}
|
|
if option.Kind == "list" {
|
|
if option.Elements().IsFilePath {
|
|
if arr, ok := v.([]string); ok {
|
|
return core.Map(arr, func(item string) string {
|
|
return tspath.GetNormalizedAbsolutePath(item, cwd)
|
|
}), true
|
|
}
|
|
}
|
|
} else if option.IsFilePath {
|
|
if value, ok := v.(string); ok {
|
|
return tspath.GetNormalizedAbsolutePath(value, cwd), true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|