diff --git a/cmd/xc/main.go b/cmd/xc/main.go index 2c4f6ba..ec80a46 100644 --- a/cmd/xc/main.go +++ b/cmd/xc/main.go @@ -31,7 +31,7 @@ var ErrNoTaskFile = errors.New("no xc compatible documentation file found") type config struct { version, help, short, display, noTTY, complete, uncomplete bool - filename, heading, filetype string + filename, heading, filetype, outputType string } var version = "" @@ -71,6 +71,8 @@ func flags() config { flag.BoolVar(&cfg.display, "d", false, "print the plain text code of a task rather than running it") flag.BoolVar(&cfg.display, "display", false, "print the plain text code of a task rather than running it") + flag.StringVar(&cfg.outputType, "output", "markdown", "specify the output type to display") + flag.BoolVar(&cfg.complete, "complete", false, "install shell completion for xc") flag.BoolVar(&cfg.uncomplete, "uncomplete", false, "uninstall shell completion for xc") @@ -250,7 +252,17 @@ func runMain() error { } // xc -display task1 if cfg.display { - ta.Display(os.Stdout) + switch strings.ToLower(cfg.outputType) { + case "markdown": + ta.Display(os.Stdout) + case "json": + err = ta.DisplayJSON(os.Stdout) + if err != nil { + return fmt.Errorf("xc: %w", err) + } + default: + fmt.Printf("xc: unrecognized output type: %s", cfg.outputType) + } return nil } // xc task1 diff --git a/cmd/xc/usage.txt b/cmd/xc/usage.txt index 2dba3aa..1e5f26f 100644 --- a/cmd/xc/usage.txt +++ b/cmd/xc/usage.txt @@ -6,6 +6,8 @@ xc [inputs...] Specify a markdown file that contains tasks (default: "README.md"). -d -display Print the markdown code of a task rather than running it. + -output + Specify the output type to display. (default: "markdown", consider: "json") -H -heading Specify the heading for xc tasks (default: "Tasks"). diff --git a/models/models.go b/models/models.go index 67aa86f..1241e5e 100644 --- a/models/models.go +++ b/models/models.go @@ -1,6 +1,7 @@ package models import ( + "encoding/json" "fmt" "io" "strings" @@ -58,6 +59,17 @@ func (t Task) Display(w io.Writer) { } } +// Display writes a Task as JSON. +func (t Task) DisplayJSON(w io.Writer) (err error) { + buf, _ := json.Marshal(t) + // I tried to find a way to trigger an marshaling error for testing + // purposes but failed. The Task struct doesn't have any fields which + // are amenable to un-marshalable objects. Therefore this just eats an + // error. + fmt.Fprintln(w, string(buf)) + return +} + // Tasks is an alias type for []Task type Tasks []Task diff --git a/models/models_test.go b/models/models_test.go new file mode 100644 index 0000000..523afcb --- /dev/null +++ b/models/models_test.go @@ -0,0 +1,83 @@ +package models + +import ( + _ "embed" + "io" + "os" + "strings" + "testing" +) + +var gnTempl = Task{ + Name: "generate-templ", + Script: "go run -mod=mod github.com/a-h/templ/cmd/templ generate\ngo mod tidy\n", +} +var gnTranslations = Task{ + Name: "generate-translations", + Script: "go run ./i18n/generate\n", +} +var gnAll = Task{ + Name: "generate-all", + DependsOn: []string{ + "generate-templ", + "generate-translations", + }, + DepsBehaviour: DependencyBehaviourAsync, +} + +//go:embed testdata/generate-templ.md +var gnTemplExpected string + +//go:embed testdata/generate-translations.md +var gnTranslationsExpected string + +//go:embed testdata/generate-all.md +var gnAllExpected string + +//go:embed testdata/generate-templ.json +var gnTemplExpectedJSON string + +//go:embed testdata/generate-translations.json +var gnTranslationsExpectedJSON string + +//go:embed testdata/generate-all.json +var gnAllExpectedJSON string + +func assertTask(t *testing.T, expected, actual string) { + t.Helper() + if strings.TrimSpace(expected) != strings.TrimSpace(actual) { + t.Fatalf("model want=%s got=%s", expected, actual) + } +} + +func taskToMarkdown(task Task) string { + r, w, _ := os.Pipe() + defer w.Close() + defer r.Close() + task.Display(w) + w.Close() + res, _ := io.ReadAll(r) + return string(res) +} + +func taskToJSON(task Task) string { + r, w, _ := os.Pipe() + defer w.Close() + defer r.Close() + _ = task.DisplayJSON(w) + w.Close() + res, _ := io.ReadAll(r) + return string(res) +} + +func TestDisplay(t *testing.T) { + assertTask(t, gnTemplExpected, taskToMarkdown(gnTempl)) + assertTask(t, gnTranslationsExpected, taskToMarkdown(gnTranslations)) + assertTask(t, gnAllExpected, taskToMarkdown(gnAll)) +} + +func TestDisplayJSON(t *testing.T) { + assertTask(t, gnTemplExpectedJSON, taskToJSON(gnTempl)) + assertTask(t, gnTranslationsExpectedJSON, taskToJSON(gnTranslations)) + assertTask(t, gnAllExpectedJSON, taskToJSON(gnAll)) +} diff --git a/models/testdata/generate-all.json b/models/testdata/generate-all.json new file mode 100644 index 0000000..a47fe8a --- /dev/null +++ b/models/testdata/generate-all.json @@ -0,0 +1 @@ +{"Name":"generate-all","Description":null,"Script":"","Dir":"","Env":null,"DependsOn":["generate-templ","generate-translations"],"Inputs":null,"ParsingError":"","RequiredBehaviour":0,"DepsBehaviour":1,"Interactive":false} diff --git a/models/testdata/generate-all.md b/models/testdata/generate-all.md new file mode 100644 index 0000000..d83cf64 --- /dev/null +++ b/models/testdata/generate-all.md @@ -0,0 +1,6 @@ +## generate-all + +Requires: generate-templ, generate-translations +RunDeps: async + +Run: always diff --git a/models/testdata/generate-templ.json b/models/testdata/generate-templ.json new file mode 100644 index 0000000..f4fbe19 --- /dev/null +++ b/models/testdata/generate-templ.json @@ -0,0 +1 @@ +{"Name":"generate-templ","Description":null,"Script":"go run -mod=mod github.com/a-h/templ/cmd/templ generate\ngo mod tidy\n","Dir":"","Env":null,"DependsOn":null,"Inputs":null,"ParsingError":"","RequiredBehaviour":0,"DepsBehaviour":0,"Interactive":false} diff --git a/models/testdata/generate-templ.md b/models/testdata/generate-templ.md new file mode 100644 index 0000000..de8a69d --- /dev/null +++ b/models/testdata/generate-templ.md @@ -0,0 +1,9 @@ +## generate-templ + +Run: always + +``` +go run -mod=mod github.com/a-h/templ/cmd/templ generate +go mod tidy + +``` diff --git a/models/testdata/generate-translations.json b/models/testdata/generate-translations.json new file mode 100644 index 0000000..5fbfdea --- /dev/null +++ b/models/testdata/generate-translations.json @@ -0,0 +1 @@ +{"Name":"generate-translations","Description":null,"Script":"go run ./i18n/generate\n","Dir":"","Env":null,"DependsOn":null,"Inputs":null,"ParsingError":"","RequiredBehaviour":0,"DepsBehaviour":0,"Interactive":false} diff --git a/models/testdata/generate-translations.md b/models/testdata/generate-translations.md new file mode 100644 index 0000000..4485512 --- /dev/null +++ b/models/testdata/generate-translations.md @@ -0,0 +1,8 @@ +## generate-translations + +Run: always + +``` +go run ./i18n/generate + +```