This repository has no description
1package main
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "os"
8 "os/exec"
9 "strings"
10
11 "git.inpt.fr/churros/notella"
12 "github.com/invopop/jsonschema"
13
14 esbuild "github.com/evanw/esbuild/pkg/api"
15 ll "github.com/gwennlbh/label-logger-go"
16)
17
18func main() {
19 ll.Log("Reflecting", "cyan", "structs")
20 reflector := new(jsonschema.Reflector)
21 if err := reflector.AddGoComments("git.inpt.fr/churros/notella", "./"); err != nil {
22 fmt.Printf("Error adding Go comments: %v\n", err)
23 }
24
25 ll.Log("Writing", "cyan", "typescript types")
26 writeTypescriptDefinition(reflector, "Message", ¬ella.Message{}, "typescript/message.ts")
27 writeTypescriptDefinition(reflector, "HealthResponse", ¬ella.HealthResponse{}, "typescript/health.ts")
28 reflector.FieldNameTag = "env"
29 writeTypescriptDefinition(reflector, "Configuration", ¬ella.Configuration{}, "typescript/configuration.ts")
30
31 // Also save useful constants
32 ll.Log("Writing", "cyan", "exported constants")
33 os.WriteFile("typescript/constants.ts", []byte(fmt.Sprintf("export const STREAM_NAME = '%s';\nexport const SUBJECT_NAME = '%s';\n", notella.StreamName, notella.SubjectName)), 0644)
34
35 // Write barrel
36 ll.Log("Writing", "cyan", "barrel file")
37 os.WriteFile("typescript/index.ts", []byte(strings.Join([]string{
38 "export * from './message.js';",
39 "export * from './configuration.js';",
40 "export * from './health.js';",
41 "export * from './constants.js';",
42 }, "\n")), 0644)
43
44 ll.Log("Transpiling", "cyan", "to JS using esbuild")
45 result := esbuild.Build(esbuild.BuildOptions{
46 EntryPoints: []string{"typescript/index.ts"},
47 Outdir: "typescript-dist/",
48 Bundle: true,
49 Sourcemap: esbuild.SourceMapLinked,
50 Format: esbuild.FormatESModule,
51 Platform: esbuild.PlatformNeutral,
52 })
53
54 for _, msg := range result.Warnings {
55 ll.Warn(formatEsbuildMessage(msg))
56 }
57
58 if len(result.Errors) > 0 {
59 for _, msg := range result.Errors {
60 ll.Error(formatEsbuildMessage(msg))
61 os.Exit(1)
62 }
63 } else {
64 for _, file := range result.OutputFiles {
65 err := os.WriteFile(file.Path, file.Contents, 0o677)
66 if err != nil {
67 ll.ErrorDisplay("could not write %s [%s]", err, file.Path, file.Hash)
68 os.Exit(1)
69 }
70 ll.Log("Wrote", "blue", "%s [dim][%s][reset]", file.Path, file.Hash)
71 }
72 ll.Log("Built", "green", "typescript library to [bold]typescript-dist/[reset]")
73 }
74}
75
76func formatEsbuildMessage(msg esbuild.Message) string {
77 notes := ""
78 for _, note := range msg.Notes {
79 notes += fmt.Sprintf("\nat %s: %s", formatEsbuildLocation(note.Location), note.Text)
80 }
81 return fmt.Sprintf("at %s: %s%s", formatEsbuildLocation(msg.Location), msg.Text, notes)
82}
83
84func formatEsbuildLocation(loc *esbuild.Location) string {
85 if loc == nil {
86 return ""
87 }
88 return fmt.Sprintf("[blue]%s:%d:%d[reset]", loc.File, loc.Line, loc.Column)
89}
90
91func writeTypescriptDefinition(reflector *jsonschema.Reflector, typename string, typ interface{}, filename string) {
92 schema := reflector.Reflect(typ)
93 schemaJSON, err := json.Marshal(schema)
94 if err != nil {
95 fmt.Printf("Error generating schema: %v\n", err)
96 return
97 }
98
99 // Set up quicktype command to read from stdin
100 cmd := exec.Command("npm", "exec", "quicktype", "--", "--lang=ts", "--src-lang=schema", "--just-types", fmt.Sprintf("--top-level=%s", typename))
101
102 // Create a pipe to stdin for the quicktype command
103 stdin, err := cmd.StdinPipe()
104 if err != nil {
105 fmt.Printf("Error creating stdin pipe: %v\n", err)
106 return
107 }
108
109 stdout, err := cmd.StdoutPipe()
110 if err != nil {
111 fmt.Printf("Error creating stdout pipe: %v\n", err)
112 return
113 }
114
115 stderr, err := cmd.StderrPipe() // Create a pipe for stderr
116 if err != nil {
117 fmt.Printf("Error creating stderr pipe: %v\n", err)
118 return
119 }
120
121 // Start the command
122 if err := cmd.Start(); err != nil {
123 fmt.Printf("Error starting quicktype: %v\n", err)
124 return
125 }
126
127 // Write the JSON schema to quicktype's stdin
128 _, err = stdin.Write(schemaJSON)
129 if err != nil {
130 fmt.Printf("Error writing to stdin: %v\n", err)
131 return
132 }
133 stdin.Close() // Important to close the pipe to signal EOF to quicktype
134
135 output, err := io.ReadAll(stdout)
136 if err != nil {
137 fmt.Printf("Error reading from stdout: %v\n", err)
138 return
139 }
140
141 // Read any error messages from quicktype's stderr
142 errorOutput, err := io.ReadAll(stderr)
143 if err != nil {
144 fmt.Printf("Error reading quicktype stderr: %v\n", err)
145 return
146 }
147
148 // Wait for the command to finish
149 if err := cmd.Wait(); err != nil {
150 fmt.Printf("Error waiting for quicktype command: %v\n", err)
151 // Print the stderr output in case of an error
152 fmt.Printf("Quicktype stderr: %s\n", errorOutput)
153 return
154 }
155
156 // Print or save the TypeScript output
157 os.WriteFile(filename, output, 0644)
158}