|
1 | 1 | package tsoptions
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "fmt" |
| 5 | + "reflect" |
4 | 6 | "strconv"
|
5 | 7 | "strings"
|
6 | 8 |
|
@@ -393,3 +395,173 @@ func convertJsonOptionOfEnumType(
|
393 | 395 | }
|
394 | 396 | return nil, []*ast.Diagnostic{createDiagnosticForInvalidEnumType(opt, sourceFile, valueExpression)}
|
395 | 397 | }
|
| 398 | + |
| 399 | +// GenerateTSConfig generates a tsconfig.json configuration when running command line "--init" |
| 400 | +func GenerateTSConfig(options *core.CompilerOptions, newLine string) string { |
| 401 | + tab := " " |
| 402 | + result := []string{} |
| 403 | + |
| 404 | + result = append(result, "{") |
| 405 | + result = append(result, tab+"// "+diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file.Format()) |
| 406 | + result = append(result, tab+"\"compilerOptions\": {") |
| 407 | + |
| 408 | + emitHeader := func(header *diagnostics.Message) { |
| 409 | + result = append(result, tab+tab+"// "+header.Format()) |
| 410 | + } |
| 411 | + |
| 412 | + newline := func() { |
| 413 | + result = append(result, "") |
| 414 | + } |
| 415 | + |
| 416 | + emitOption := func(setting string, defaultValue any, commented ...string) { |
| 417 | + commentMode := "never" |
| 418 | + if len(commented) > 0 { |
| 419 | + commentMode = commented[0] |
| 420 | + } |
| 421 | + |
| 422 | + var comment bool |
| 423 | + if commentMode == "always" { |
| 424 | + comment = true |
| 425 | + } else if commentMode == "never" { |
| 426 | + comment = false |
| 427 | + } else { |
| 428 | + // "optional" - always comment out for the template |
| 429 | + comment = true |
| 430 | + } |
| 431 | + |
| 432 | + formattedValue := formatValueOrArray(setting, defaultValue) |
| 433 | + |
| 434 | + if comment { |
| 435 | + result = append(result, tab+tab+"// \""+setting+"\": "+formattedValue+",") |
| 436 | + } else { |
| 437 | + result = append(result, tab+tab+"\""+setting+"\": "+formattedValue+",") |
| 438 | + } |
| 439 | + } |
| 440 | + |
| 441 | + // File Layout |
| 442 | + emitHeader(diagnostics.File_Layout) |
| 443 | + emitOption("rootDir", "./src", "optional") |
| 444 | + emitOption("outDir", "./dist", "optional") |
| 445 | + |
| 446 | + newline() |
| 447 | + |
| 448 | + // Environment Settings |
| 449 | + emitHeader(diagnostics.Environment_Settings) |
| 450 | + emitHeader(diagnostics.See_also_https_Colon_Slash_Slashaka_ms_Slashtsconfig_Slashmodule) |
| 451 | + emitOption("module", core.ModuleKindNodeNext) |
| 452 | + emitOption("target", core.ScriptTargetESNext) |
| 453 | + emitOption("types", []any{}) |
| 454 | + if options.Lib != nil && len(options.Lib) > 0 { |
| 455 | + emitOption("lib", options.Lib) |
| 456 | + } |
| 457 | + emitHeader(diagnostics.For_nodejs_Colon) |
| 458 | + result = append(result, tab+tab+"// \"lib\": [\"esnext\"],") |
| 459 | + result = append(result, tab+tab+"// \"types\": [\"node\"],") |
| 460 | + emitHeader(diagnostics.X_and_npm_install_D_types_Slashnode) |
| 461 | + |
| 462 | + newline() |
| 463 | + |
| 464 | + // Other Outputs |
| 465 | + emitHeader(diagnostics.Other_Outputs) |
| 466 | + emitOption("sourceMap", true) |
| 467 | + emitOption("declaration", true) |
| 468 | + emitOption("declarationMap", true) |
| 469 | + |
| 470 | + newline() |
| 471 | + |
| 472 | + // Stricter Typechecking Options |
| 473 | + emitHeader(diagnostics.Stricter_Typechecking_Options) |
| 474 | + emitOption("noUncheckedIndexedAccess", true) |
| 475 | + emitOption("exactOptionalPropertyTypes", true) |
| 476 | + |
| 477 | + newline() |
| 478 | + |
| 479 | + // Style Options |
| 480 | + emitHeader(diagnostics.Style_Options) |
| 481 | + emitOption("noImplicitReturns", true, "optional") |
| 482 | + emitOption("noImplicitOverride", true, "optional") |
| 483 | + emitOption("noUnusedLocals", true, "optional") |
| 484 | + emitOption("noUnusedParameters", true, "optional") |
| 485 | + emitOption("noFallthroughCasesInSwitch", true, "optional") |
| 486 | + emitOption("noPropertyAccessFromIndexSignature", true, "optional") |
| 487 | + |
| 488 | + newline() |
| 489 | + |
| 490 | + // Recommended Options |
| 491 | + emitHeader(diagnostics.Recommended_Options) |
| 492 | + emitOption("strict", true) |
| 493 | + emitOption("jsx", core.JsxEmitReactJSX) |
| 494 | + emitOption("verbatimModuleSyntax", true) |
| 495 | + emitOption("isolatedModules", true) |
| 496 | + emitOption("noUncheckedSideEffectImports", true) |
| 497 | + emitOption("moduleDetection", core.ModuleDetectionKindForce) |
| 498 | + // Last option - no trailing comma |
| 499 | + result = append(result, tab+tab+"\"skipLibCheck\": true") |
| 500 | + |
| 501 | + result = append(result, tab+"}") |
| 502 | + result = append(result, "}") |
| 503 | + result = append(result, "") |
| 504 | + |
| 505 | + return strings.Join(result, newLine) |
| 506 | +} |
| 507 | + |
| 508 | +func formatValueOrArray(settingName string, value any) string { |
| 509 | + option := CommandLineCompilerOptionsMap.Get(settingName) |
| 510 | + if option == nil { |
| 511 | + // Fallback for unknown options |
| 512 | + return formatSingleValue(value, nil) |
| 513 | + } |
| 514 | + |
| 515 | + typeMap := option.EnumMap() |
| 516 | + |
| 517 | + // Handle array values |
| 518 | + if v, ok := value.([]any); ok { |
| 519 | + var elementMap *collections.OrderedMap[string, any] |
| 520 | + if element := option.Elements(); element != nil { |
| 521 | + elementMap = element.EnumMap() |
| 522 | + } |
| 523 | + formattedValues := make([]string, len(v)) |
| 524 | + for i, item := range v { |
| 525 | + formattedValues[i] = formatSingleValue(item, elementMap) |
| 526 | + } |
| 527 | + return "[" + strings.Join(formattedValues, ", ") + "]" |
| 528 | + } |
| 529 | + |
| 530 | + // Handle string array (lib option) |
| 531 | + if v, ok := value.([]string); ok { |
| 532 | + formattedValues := make([]string, len(v)) |
| 533 | + for i, item := range v { |
| 534 | + formattedValues[i] = formatSingleValue(item, nil) |
| 535 | + } |
| 536 | + return "[" + strings.Join(formattedValues, ", ") + "]" |
| 537 | + } |
| 538 | + |
| 539 | + return formatSingleValue(value, typeMap) |
| 540 | +} |
| 541 | + |
| 542 | +func formatSingleValue(value any, typeMap *collections.OrderedMap[string, any]) string { |
| 543 | + if typeMap != nil { |
| 544 | + // Find the key for this enum value |
| 545 | + for k, v := range typeMap.Entries() { |
| 546 | + if v == value { |
| 547 | + value = k |
| 548 | + break |
| 549 | + } |
| 550 | + } |
| 551 | + } |
| 552 | + |
| 553 | + // Handle different types |
| 554 | + switch v := value.(type) { |
| 555 | + case string: |
| 556 | + return strconv.Quote(v) |
| 557 | + case bool: |
| 558 | + return strconv.FormatBool(v) |
| 559 | + case int, int32, int64: |
| 560 | + return strconv.FormatInt(reflect.ValueOf(v).Int(), 10) |
| 561 | + case float32, float64: |
| 562 | + return strconv.FormatFloat(reflect.ValueOf(v).Float(), 'f', -1, 64) |
| 563 | + default: |
| 564 | + // For unknown types, use string representation |
| 565 | + return strconv.Quote(fmt.Sprintf("%v", v)) |
| 566 | + } |
| 567 | +} |
0 commit comments