Skip to content

Port part of tsc help from strada #636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 18, 2025
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions internal/core/compileroptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ type CompilerOptions struct {
Watch Tristate `json:"watch,omitzero"`
ShowConfig Tristate `json:"showConfig,omitzero"`
TscBuild Tristate `json:"tscBuild,omitzero"`
Help Tristate `json:"help,omitzero"`
All Tristate `json:"all,omitzero"`
}

func (options *CompilerOptions) GetEmitScriptTarget() ScriptTarget {
Expand Down
185 changes: 185 additions & 0 deletions internal/execute/outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package execute

import (
"fmt"
"slices"
"strings"

"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/compiler"
"github.com/microsoft/typescript-go/internal/compiler/diagnostics"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/diagnosticwriter"
"github.com/microsoft/typescript-go/internal/tsoptions"
"github.com/microsoft/typescript-go/internal/tspath"
)

Expand Down Expand Up @@ -85,3 +87,186 @@ func printVersion(sys System) {
fmt.Fprint(sys.Writer(), diagnostics.Version_0.Format(core.Version)+sys.NewLine())
sys.EndWrite()
}

func printHelp(sys System, commandLine *tsoptions.ParsedCommandLine) {
if commandLine.CompilerOptions().All.IsFalseOrUnknown() {
printEasyHelp(sys, getOptionsForHelp(commandLine))
} else {
// !!! printAllHelp(sys, getOptionsForHelp(commandLine))
}
}

func getOptionsForHelp(commandLine *tsoptions.ParsedCommandLine) []*tsoptions.CommandLineOption {
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
opts := slices.Clone(tsoptions.OptionsDeclarations)
opts = append(opts, &tsoptions.TscBuildOption)

if commandLine.CompilerOptions().All.IsTrue() {
slices.SortFunc(opts, func(a, b *tsoptions.CommandLineOption) int {
return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name))
})
return opts
} else {
return core.Filter(opts, func(opt *tsoptions.CommandLineOption) bool {
return opt.ShowInSimplifiedHelpView
})
}
}

func getHeader(sys System, message string) []string {
// !!! const colors = createColors(sys);
var header []string
// !!! terminalWidth := sys.GetWidthOfTerminal?.() ?? 0
const tsIconLength = 5

// const tsIconFirstLine = colors.blueBackground("".padStart(tsIconLength));
// const tsIconSecondLine = colors.blueBackground(colors.brightWhite("TS ".padStart(tsIconLength)));
// // If we have enough space, print TS icon.
// if (terminalWidth >= message.length + tsIconLength) {
// // right align of the icon is 120 at most.
// const rightAlign = terminalWidth > 120 ? 120 : terminalWidth;
// const leftAlign = rightAlign - tsIconLength;
// header.push(message.padEnd(leftAlign) + tsIconFirstLine + sys.newLine);
// header.push("".padStart(leftAlign) + tsIconSecondLine + sys.newLine);
// }
// else {
header = append(header, message+sys.NewLine(), sys.NewLine())
// }
return header
}

func printEasyHelp(sys System, simpleOptions []*tsoptions.CommandLineOption) {
// !!! const colors = createColors(sys);
var output []string
example := func(examples []string, desc *diagnostics.Message) {
for _, example := range examples {
// !!! colors
// output.push(" " + colors.blue(example) + sys.newLine);
output = append(output, " ", example, sys.NewLine())
}
output = append(output, " ", desc.Format(), sys.NewLine(), sys.NewLine())
}

msg := diagnostics.X_tsc_Colon_The_TypeScript_Compiler.Format() + " - " + diagnostics.Version_0.Format(core.Version)
output = append(output, getHeader(sys, msg)...)

output = append(output /*colors.bold(*/, diagnostics.COMMON_COMMANDS.Format() /*)*/, sys.NewLine(), sys.NewLine())

example([]string{"tsc"}, diagnostics.Compiles_the_current_project_tsconfig_json_in_the_working_directory)
example([]string{"tsc app.ts util.ts"}, diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options)
example([]string{"tsc -b"}, diagnostics.Build_a_composite_project_in_the_working_directory)
example([]string{"tsc --init"}, diagnostics.Creates_a_tsconfig_json_with_the_recommended_settings_in_the_working_directory)
example([]string{"tsc -p ./path/to/tsconfig.json"}, diagnostics.Compiles_the_TypeScript_project_located_at_the_specified_path)
example([]string{"tsc --help --all"}, diagnostics.An_expanded_version_of_this_information_showing_all_possible_compiler_options)
example([]string{"tsc --noEmit", "tsc --target esnext"}, diagnostics.Compiles_the_current_project_with_additional_settings)

var cliCommands []*tsoptions.CommandLineOption
var configOpts []*tsoptions.CommandLineOption
for _, opt := range simpleOptions {
if opt.IsCommandLineOnly || opt.Category == diagnostics.Command_line_Options {
cliCommands = append(cliCommands, opt)
} else {
configOpts = append(configOpts, opt)
}
}

output = append(output, generateSectionOptionsOutput(sys, diagnostics.COMMAND_LINE_FLAGS.Format(), cliCommands /*subCategory*/, false /*beforeOptionsDescription*/, nil /*afterOptionsDescription*/, nil)...)

after := diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0.Format("https://aka.ms/tsc")
output = append(output, generateSectionOptionsOutput(sys, diagnostics.COMMON_COMPILER_OPTIONS.Format(), configOpts /*subCategory*/, false /*beforeOptionsDescription*/, nil,
// !!! locale formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc")),
&after)...)

for _, chunk := range output {
fmt.Fprint(sys.Writer(), chunk)
}
sys.EndWrite()
}

func generateSectionOptionsOutput(
sys System,
sectionName string,
options []*tsoptions.CommandLineOption,
subCategory bool,
beforeOptionsDescription,
afterOptionsDescription *string,
) (output []string) {
// !!! color
output = append(output /*createColors(sys).bold(*/, sectionName /*)*/, sys.NewLine(), sys.NewLine())

if beforeOptionsDescription != nil {
output = append(output, *beforeOptionsDescription, sys.NewLine(), sys.NewLine())
}
if !subCategory {
output = append(output, generateGroupOptionOutput(sys, options)...)
if afterOptionsDescription != nil {
output = append(output, *afterOptionsDescription, sys.NewLine(), sys.NewLine())
}
return output
}
categoryMap := make(map[string][]*tsoptions.CommandLineOption)
for _, option := range options {
if option.Category == nil {
continue
}
curCategory := option.Category.Format()
categoryMap[curCategory] = append(categoryMap[curCategory], option)
}
for key, value := range categoryMap {
output = append(output, "### ", key, sys.NewLine(), sys.NewLine())
output = append(output, generateGroupOptionOutput(sys, value)...)
}
if afterOptionsDescription != nil {
output = append(output, *afterOptionsDescription, sys.NewLine(), sys.NewLine())
}

return output
}

func generateGroupOptionOutput(sys System, optionsList []*tsoptions.CommandLineOption) []string {
var maxLength int
for _, option := range optionsList {
curLenght := len(getDisplayNameTextOfOption(option))
maxLength = max(curLenght, maxLength)
}

// left part should be right align, right part should be left align

// assume 2 space between left margin and left part.
rightAlignOfLeftPart := maxLength + 2
// assume 2 space between left and right part
leftAlignOfRightPart := rightAlignOfLeftPart + 2

var lines []string
for _, option := range optionsList {
tmp := generateOptionOutput(sys, option, rightAlignOfLeftPart, leftAlignOfRightPart)
lines = append(lines, tmp...)
}

// make sure always a blank line in the end.
// !!! if lines[len(lines)-2] != sys.NewLine() {
// !!! lines = append(lines, sys.NewLine())
// !!! }

return lines
}

func generateOptionOutput(
sys System,
option *tsoptions.CommandLineOption,
rightAlignOfLeftPart, leftAlignOfRightPart int,
) []string {
var text []string
// !!! const colors = createColors(sys);

// name and description
// !!! name := getDisplayNameTextOfOption(option)

// !!!

return text
}

func getDisplayNameTextOfOption(option *tsoptions.CommandLineOption) string {
return "--" + option.Name + core.IfElse(option.ShortName != "", ", -"+option.ShortName, "")
}
16 changes: 11 additions & 5 deletions internal/execute/tsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ func executeCommandLineWorker(sys System, cb cbType, commandLine *tsoptions.Pars
return ExitStatusDiagnosticsPresent_OutputsSkipped, nil
}

if commandLine.CompilerOptions().Init.IsTrue() ||
// commandLine.CompilerOptions().Help != nil ||
// commandLine.CompilerOptions().All != nil ||
commandLine.CompilerOptions().Watch.IsTrue() && commandLine.CompilerOptions().ListFilesOnly.IsTrue() {
if commandLine.CompilerOptions().Init.IsTrue() {
return ExitStatusNotImplemented, nil
}

Expand All @@ -46,6 +43,15 @@ func executeCommandLineWorker(sys System, cb cbType, commandLine *tsoptions.Pars
return ExitStatusSuccess, nil
}

if commandLine.CompilerOptions().Help.IsTrue() || commandLine.CompilerOptions().All.IsTrue() {
printHelp(sys, commandLine)
return ExitStatusSuccess, nil
}

if commandLine.CompilerOptions().Watch.IsTrue() && commandLine.CompilerOptions().ListFilesOnly.IsTrue() {
return ExitStatusNotImplemented, nil
}

if commandLine.CompilerOptions().Project != "" {
if len(commandLine.FileNames()) != 0 {
reportDiagnostic(ast.NewCompilerDiagnostic(diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line))
Expand Down Expand Up @@ -76,7 +82,7 @@ func executeCommandLineWorker(sys System, cb cbType, commandLine *tsoptions.Pars
reportDiagnostic(ast.NewCompilerDiagnostic(diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, tspath.NormalizePath(sys.GetCurrentDirectory())))
} else {
printVersion(sys)
// print help
printHelp(sys, commandLine)
}
return ExitStatusDiagnosticsPresent_OutputsSkipped, nil
}
Expand Down
4 changes: 2 additions & 2 deletions internal/tsoptions/commandlineoption.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const (
)

type CommandLineOption struct {
Name, shortName string
Name, ShortName string
Kind CommandLineOptionKind

// used in parsing
Expand All @@ -30,7 +30,7 @@ type CommandLineOption struct {
// used in output
Description *diagnostics.Message
DefaultValueDescription any
showInSimplifiedHelpView bool
ShowInSimplifiedHelpView bool

// used in output in serializing and generate tsconfig
Category *diagnostics.Message
Expand Down
14 changes: 7 additions & 7 deletions internal/tsoptions/declsbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,37 @@ import (

var BuildOpts = slices.Concat(commonOptionsWithBuild, optionsForBuild)

var tscBuildOption = CommandLineOption{
var TscBuildOption = CommandLineOption{
Name: "build",
Kind: "boolean",
shortName: "b",
showInSimplifiedHelpView: true,
ShortName: "b",
ShowInSimplifiedHelpView: true,
Category: diagnostics.Command_line_Options,
Description: diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date,
DefaultValueDescription: false,
}

var optionsForBuild = []*CommandLineOption{
&tscBuildOption,
&TscBuildOption,
{
Name: "verbose",
shortName: "v",
ShortName: "v",
Category: diagnostics.Command_line_Options,
Description: diagnostics.Enable_verbose_logging,
Kind: "boolean",
DefaultValueDescription: false,
},
{
Name: "dry",
shortName: "d",
ShortName: "d",
Category: diagnostics.Command_line_Options,
Description: diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
Kind: "boolean",
DefaultValueDescription: false,
},
{
Name: "force",
shortName: "f",
ShortName: "f",
Category: diagnostics.Command_line_Options,
Description: diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
Kind: "boolean",
Expand Down
Loading