├── test ├── package.json ├── htmldocs │ ├── .nojekyll │ ├── assets │ │ └── highlight.css │ ├── types │ │ ├── _TygojaAny.html │ │ ├── _TygojaDict.html │ │ └── a._subOLPog.html │ ├── functions │ │ └── _app.html │ ├── modules.html │ ├── modules │ │ ├── c.html │ │ └── b.html │ └── interfaces │ │ ├── a.Empty.html │ │ ├── c.Handler.html │ │ ├── b.Func1.html │ │ ├── b.Func7.html │ │ ├── b.Func8.html │ │ ├── b.Func2.html │ │ ├── b.Func9.html │ │ ├── b.Func4.html │ │ ├── b.Func5.html │ │ └── a.Handler.html ├── tsconfig.json ├── a │ ├── interfaces.go │ ├── structs.go │ └── vars.go ├── main.go ├── b │ └── functions.go ├── c │ └── c.go └── package-lock.json ├── go.mod ├── .gitignore ├── go.sum ├── random.go ├── iota.go ├── LICENSE ├── write_comment.go ├── config.go ├── package_generator.go ├── README.md └── tygoja.go /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "generate": "npx typedoc" 4 | }, 5 | "devDependencies": { 6 | "typedoc": "^0.24.8" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/htmldocs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "typedocOptions": { 3 | "entryPoints": ["types.d.ts"], 4 | "skipErrorChecking": true, 5 | "out": "htmldocs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/pocketbase/tygoja 2 | 3 | go 1.22.0 4 | 5 | require golang.org/x/tools v0.26.0 6 | 7 | require ( 8 | golang.org/x/mod v0.21.0 // indirect 9 | golang.org/x/sync v0.8.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode/ 2 | .idea 3 | 4 | .DS_Store 5 | 6 | # tests coverage 7 | coverage.out 8 | 9 | # test data artifacts 10 | test/node_modules/ 11 | test/output.json 12 | 13 | # plaintask todo files 14 | *.todo 15 | 16 | # generated markdown previews 17 | README.html 18 | CHANGELOG.html 19 | LICENSE.html 20 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= 2 | golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 3 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 4 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 5 | golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= 6 | golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 7 | -------------------------------------------------------------------------------- /test/a/interfaces.go: -------------------------------------------------------------------------------- 1 | package a 2 | 3 | import "time" 4 | 5 | type Empty interface{} 6 | 7 | // unexported interface 8 | type interfaceA[T any] interface { 9 | // some comment 10 | unexportedFunc() 11 | 12 | // some comment above the function 13 | Method0() 14 | 15 | Method1() string // inline comment 16 | 17 | // multi 18 | // line 19 | // comment 20 | Method2(argA, argB string) (T, int) 21 | 22 | Method3(argA int, argB ...string) (T, []string, error) 23 | } 24 | 25 | // multi 26 | // line 27 | // comment 28 | type InterfaceB interface { 29 | Empty 30 | interfaceA[int] 31 | 32 | // "replace" Method0 from interfaceA 33 | Method0() 34 | 35 | CustomMethod() time.Time 36 | } 37 | -------------------------------------------------------------------------------- /random.go: -------------------------------------------------------------------------------- 1 | package tygoja 2 | 3 | import ( 4 | mathRand "math/rand" 5 | "time" 6 | ) 7 | 8 | const defaultRandomAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 9 | 10 | func init() { 11 | mathRand.Seed(time.Now().UnixNano()) 12 | } 13 | 14 | // PseudorandomString generates a pseudorandom string from the default 15 | // alphabet with the specified length. 16 | func PseudorandomString(length int) string { 17 | return PseudorandomStringWithAlphabet(length, defaultRandomAlphabet) 18 | } 19 | 20 | // PseudorandomStringWithAlphabet generates a pseudorandom string 21 | // with the specified length and characters set. 22 | func PseudorandomStringWithAlphabet(length int, alphabet string) string { 23 | b := make([]byte, length) 24 | max := len(alphabet) 25 | 26 | for i := range b { 27 | b[i] = alphabet[mathRand.Intn(max)] 28 | } 29 | 30 | return string(b) 31 | } 32 | -------------------------------------------------------------------------------- /test/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/pocketbase/tygoja" 8 | ) 9 | 10 | func main() { 11 | gen := tygoja.New(tygoja.Config{ 12 | Packages: map[string][]string{ 13 | "github.com/pocketbase/tygoja/test/a": {"*"}, 14 | "github.com/pocketbase/tygoja/test/b": {"*"}, 15 | "github.com/pocketbase/tygoja/test/c": {"Example2", "Handler"}, 16 | }, 17 | Heading: `declare var $app: c.Handler;`, 18 | WithPackageFunctions: true, 19 | // enable if you want to be able to import them 20 | // StartModifier: "export", 21 | }) 22 | 23 | result, err := gen.Generate() 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | if err := os.WriteFile("./types.d.ts", []byte(result), 0644); err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | // run `npx typedoc` to generate HTML docs from the above declarations 33 | } 34 | -------------------------------------------------------------------------------- /test/a/structs.go: -------------------------------------------------------------------------------- 1 | package a 2 | 3 | type unexported struct { 4 | field0 string 5 | Field1 string 6 | } 7 | 8 | // structA comment 9 | type structA struct { 10 | Field1 string // after 11 | 12 | // multi 13 | // line 14 | // comment 15 | // with union type 16 | Field2 []byte 17 | } 18 | 19 | func (s structA) method0() {} 20 | 21 | // method comment 22 | func (s structA) Method1(arg1 int) {} 23 | 24 | func (s *structA) Method2(arg1 int, arg2 ...string) {} // after 25 | 26 | // structB comment 27 | type StructB[T any] struct { 28 | *unexported 29 | structA 30 | 31 | Field3 T 32 | } 33 | 34 | // StructB.Method3 comment 35 | func (s *StructB[T]) Method3(arg1 int) (a int, b string, c error) { 36 | return 37 | } 38 | 39 | // structC with multiple mixed generic types 40 | type StructC[A string, B, C any] struct { 41 | Field4 A 42 | Field5 B 43 | Field6 C 44 | } 45 | 46 | // StructC.Method4 comment 47 | func (s *StructC[A, B, C]) Method4(arg1 A) (a B, b C, c error) { 48 | return 49 | } 50 | -------------------------------------------------------------------------------- /iota.go: -------------------------------------------------------------------------------- 1 | package tygoja 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func isProbablyIotaType(groupType string) bool { 10 | groupType = strings.Trim(groupType, "()") 11 | return groupType == "iota" || strings.HasPrefix(groupType, "iota +") || strings.HasSuffix(groupType, "+ iota") 12 | } 13 | 14 | func basicIotaOffsetValueParse(groupType string) (int, error) { 15 | if !isProbablyIotaType(groupType) { 16 | panic("can't parse non-iota type") 17 | } 18 | 19 | groupType = strings.Trim(groupType, "()") 20 | if groupType == "iota" { 21 | return 0, nil 22 | } 23 | parts := strings.Split(groupType, " + ") 24 | 25 | var numPart string 26 | if parts[0] == "iota" { 27 | numPart = parts[1] 28 | } else { 29 | numPart = parts[0] 30 | } 31 | 32 | addValue, err := strconv.ParseInt(numPart, 10, 64) 33 | if err != nil { 34 | return 0, fmt.Errorf("Failed to guesstimate initial iota value for \"%s\": %w", groupType, err) 35 | } 36 | 37 | return int(addValue), nil 38 | } 39 | -------------------------------------------------------------------------------- /test/b/functions.go: -------------------------------------------------------------------------------- 1 | // package b 2 | package b 3 | 4 | func func0() {} 5 | 6 | // single comment 7 | func Func1() {} 8 | 9 | // multi 10 | // line 11 | // comment 12 | func Func2[T any](arg1 int) (a T, b error) { 13 | return 14 | } 15 | 16 | // function with multiple generic types 17 | func Func3[A string, B, C any](arg1 A, arg2 B, arg3 int) (a A, b C) { 18 | return 19 | } 20 | 21 | // function that returns a function 22 | func Func4(arg1 int) (a func() int) { 23 | return a 24 | } 25 | 26 | // function with ommited argument types 27 | func Func5(arg0 string, arg1, arg2 int) { 28 | } 29 | 30 | // function with reserved argument name and variadic type 31 | func Func6(catch string, optional ...string) { 32 | } 33 | 34 | // function with ommited argument names 35 | func Func7(string, int, ...bool) { 36 | } 37 | 38 | // function with named return values 39 | func Func8() (b int, c string) { 40 | return 41 | } 42 | 43 | // function with shortened return values 44 | func Func9() (b, c string) { 45 | return 46 | } 47 | 48 | // function with named and shortened return values 49 | func Func10() (a int, b, c string) { 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /test/c/c.go: -------------------------------------------------------------------------------- 1 | package c 2 | 3 | import "time" 4 | 5 | // func type comment 6 | type Handler func() string // after 7 | 8 | type Raw []byte 9 | 10 | type Example1 struct { 11 | Name string 12 | } 13 | 14 | // Example: 15 | // 16 | // Some 17 | // code 18 | // sample 19 | type Example2 struct { 20 | Title string 21 | Json Raw 22 | Bytes []byte // should be union 23 | } 24 | 25 | func (e *Example1) DemoEx1() string { 26 | return "" 27 | } 28 | 29 | func (e *Example2) DemoEx2() time.Time { 30 | return time.Time{} 31 | } 32 | 33 | // Pointer as argument vs return type 34 | func (e *Example2) DemoEx3(arg *Example1) (*Example1, error) { 35 | return nil, nil 36 | } 37 | 38 | // ommited types 39 | func (e *Example2) DemoEx4(n1, n2, n3 string) { 40 | } 41 | 42 | // ommited names 43 | func (e *Example2) DemoEx5(string, int) { 44 | } 45 | 46 | // named return values 47 | func (e *Example2) DemoEx6() (b int, c string) { 48 | return 49 | } 50 | 51 | // shortened return values 52 | func (e *Example2) DemoEx7() (b, c string) { 53 | return 54 | } 55 | 56 | // named and shortened return values 57 | func (e *Example2) DemoEx8() (a int, b, c string) { 58 | return 59 | } 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Guido Zuidhof 4 | Copyright (c) 2023-present Gani Georgiev 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /write_comment.go: -------------------------------------------------------------------------------- 1 | package tygoja 2 | 3 | import ( 4 | "go/ast" 5 | "strings" 6 | ) 7 | 8 | func (g *PackageGenerator) writeCommentGroup(s *strings.Builder, f *ast.CommentGroup, depth int) { 9 | if f == nil { 10 | return 11 | } 12 | 13 | docLines := strings.Split(f.Text(), "\n") 14 | 15 | g.writeIndent(s, depth) 16 | s.WriteString("/**\n") 17 | 18 | lastLineIdx := len(docLines) - 1 19 | 20 | var isCodeBlock bool 21 | 22 | emptySB := new(strings.Builder) 23 | 24 | for i, c := range docLines { 25 | isEndLine := i == lastLineIdx 26 | isEmpty := len(strings.TrimSpace(c)) == 0 27 | isIndented := strings.HasPrefix(c, "\t") || strings.HasPrefix(c, " ") 28 | 29 | // end code block 30 | if isCodeBlock && (isEndLine || (!isIndented && !isEmpty)) { 31 | g.writeIndent(s, depth) 32 | s.WriteString(" * ```\n") 33 | isCodeBlock = false 34 | } 35 | 36 | // accumulate empty comment lines 37 | // (this is done to properly enclose code blocks with new lines) 38 | if isEmpty { 39 | g.writeIndent(emptySB, depth) 40 | emptySB.WriteString(" * \n") 41 | } else { 42 | // write all empty lines 43 | s.WriteString(emptySB.String()) 44 | emptySB.Reset() 45 | } 46 | 47 | // start code block 48 | if isIndented && !isCodeBlock && !isEndLine { 49 | g.writeIndent(s, depth) 50 | s.WriteString(" * ```\n") 51 | isCodeBlock = true 52 | } 53 | 54 | // write comment line 55 | if !isEmpty { 56 | g.writeIndent(s, depth) 57 | s.WriteString(" * ") 58 | c = strings.ReplaceAll(c, "*/", "*\\/") // An edge case: a // comment can contain */ 59 | s.WriteString(c) 60 | s.WriteByte('\n') 61 | } 62 | } 63 | 64 | g.writeIndent(s, depth) 65 | s.WriteString(" */\n") 66 | } 67 | -------------------------------------------------------------------------------- /test/a/vars.go: -------------------------------------------------------------------------------- 1 | // package a docs 2 | // lorem ipsum dolor... 3 | package a 4 | 5 | import "time" 6 | 7 | // ------------------------------------------------------------------- 8 | // variables (note: currently are ignored) 9 | // ------------------------------------------------------------------- 10 | 11 | var unexportedVar int = 123 12 | 13 | // comment 14 | var VarA = 123 // after 15 | 16 | var VarB any = "test" 17 | 18 | // external package type 19 | var VarC time.Time = time.Now() 20 | 21 | // chan 22 | var VarD = make(chan int) 23 | 24 | // composite 25 | var VarE = map[string]func(){"test": func() {}} 26 | 27 | // ------------------------------------------------------------------- 28 | // constants 29 | // ------------------------------------------------------------------- 30 | 31 | const unexportedConst = "123" 32 | 33 | // comment 34 | const ConstA string = "test" // after 35 | 36 | // multi 37 | // line 38 | // comment 39 | const ConstB = 123 40 | 41 | // some generic group comment 42 | const ( 43 | ConstC0 = iota 44 | ConstC1 // after 45 | ConstC2 46 | ) 47 | 48 | // ------------------------------------------------------------------- 49 | // type alias with methods 50 | // ------------------------------------------------------------------- 51 | 52 | // type comment 53 | type SliceAlias[T any] []T // after 54 | 55 | // func comment 56 | func (s SliceAlias[T]) funcA() { 57 | } 58 | 59 | // multi 60 | // line 61 | // comment 62 | func (s SliceAlias[T]) funcB(argA, argB int) { 63 | } 64 | 65 | func (s SliceAlias[T]) funcC(argA int, argB ...string) (a T, b int, c error) { 66 | return 67 | } 68 | 69 | // ------------------------------------------------------------------- 70 | // function type 71 | // ------------------------------------------------------------------- 72 | 73 | // multi 74 | // line 75 | // comment 76 | type Handler[T comparable] func() (T, int) // after 77 | -------------------------------------------------------------------------------- /test/htmldocs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #0000FF; 3 | --dark-hl-0: #569CD6; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #A31515; 7 | --dark-hl-2: #CE9178; 8 | --light-hl-3: #795E26; 9 | --dark-hl-3: #DCDCAA; 10 | --light-hl-4: #001080; 11 | --dark-hl-4: #9CDCFE; 12 | --light-hl-5: #267F99; 13 | --dark-hl-5: #4EC9B0; 14 | --light-hl-6: #AF00DB; 15 | --dark-hl-6: #C586C0; 16 | --light-hl-7: #098658; 17 | --dark-hl-7: #B5CEA8; 18 | --light-hl-8: #000000; 19 | --dark-hl-8: #C8C8C8; 20 | --light-code-background: #FFFFFF; 21 | --dark-code-background: #1E1E1E; 22 | } 23 | 24 | @media (prefers-color-scheme: light) { :root { 25 | --hl-0: var(--light-hl-0); 26 | --hl-1: var(--light-hl-1); 27 | --hl-2: var(--light-hl-2); 28 | --hl-3: var(--light-hl-3); 29 | --hl-4: var(--light-hl-4); 30 | --hl-5: var(--light-hl-5); 31 | --hl-6: var(--light-hl-6); 32 | --hl-7: var(--light-hl-7); 33 | --hl-8: var(--light-hl-8); 34 | --code-background: var(--light-code-background); 35 | } } 36 | 37 | @media (prefers-color-scheme: dark) { :root { 38 | --hl-0: var(--dark-hl-0); 39 | --hl-1: var(--dark-hl-1); 40 | --hl-2: var(--dark-hl-2); 41 | --hl-3: var(--dark-hl-3); 42 | --hl-4: var(--dark-hl-4); 43 | --hl-5: var(--dark-hl-5); 44 | --hl-6: var(--dark-hl-6); 45 | --hl-7: var(--dark-hl-7); 46 | --hl-8: var(--dark-hl-8); 47 | --code-background: var(--dark-code-background); 48 | } } 49 | 50 | :root[data-theme='light'] { 51 | --hl-0: var(--light-hl-0); 52 | --hl-1: var(--light-hl-1); 53 | --hl-2: var(--light-hl-2); 54 | --hl-3: var(--light-hl-3); 55 | --hl-4: var(--light-hl-4); 56 | --hl-5: var(--light-hl-5); 57 | --hl-6: var(--light-hl-6); 58 | --hl-7: var(--light-hl-7); 59 | --hl-8: var(--light-hl-8); 60 | --code-background: var(--light-code-background); 61 | } 62 | 63 | :root[data-theme='dark'] { 64 | --hl-0: var(--dark-hl-0); 65 | --hl-1: var(--dark-hl-1); 66 | --hl-2: var(--dark-hl-2); 67 | --hl-3: var(--dark-hl-3); 68 | --hl-4: var(--dark-hl-4); 69 | --hl-5: var(--dark-hl-5); 70 | --hl-6: var(--dark-hl-6); 71 | --hl-7: var(--dark-hl-7); 72 | --hl-8: var(--dark-hl-8); 73 | --code-background: var(--dark-code-background); 74 | } 75 | 76 | .hl-0 { color: var(--hl-0); } 77 | .hl-1 { color: var(--hl-1); } 78 | .hl-2 { color: var(--hl-2); } 79 | .hl-3 { color: var(--hl-3); } 80 | .hl-4 { color: var(--hl-4); } 81 | .hl-5 { color: var(--hl-5); } 82 | .hl-6 { color: var(--hl-6); } 83 | .hl-7 { color: var(--hl-7); } 84 | .hl-8 { color: var(--hl-8); } 85 | pre, code { background: var(--code-background); } 86 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package tygoja 2 | 3 | const ( 4 | defaultIndent = " " 5 | 6 | // custom base types that every package has access to 7 | BaseTypeDict = "_TygojaDict" // Record type alternative as a more generic map-like type 8 | BaseTypeAny = "_TygojaAny" // any type alias to allow easier extends generation 9 | ) 10 | 11 | // FieldNameFormatterFunc defines a function for formatting a field name. 12 | type FieldNameFormatterFunc func(string) string 13 | 14 | // MethodNameFormatterFunc defines a function for formatting a method name. 15 | type MethodNameFormatterFunc func(string) string 16 | 17 | type Config struct { 18 | // Packages is a list of package paths just like you would import them in Go. 19 | // Use "*" to generate all package types. 20 | // 21 | // Example: 22 | // 23 | // Packages: map[string][]string{ 24 | // "time": {"Time"}, 25 | // "github.com/pocketbase/pocketbase/core": {"*"}, 26 | // } 27 | Packages map[string][]string 28 | 29 | // Heading specifies a content that will be put at the top of the output declaration file. 30 | // 31 | // You would generally use this to import custom types or some custom TS declarations. 32 | Heading string 33 | 34 | // TypeMappings specifies custom type translations. 35 | // 36 | // Useful for for mapping 3rd party package types, eg "unsafe.Pointer" => "CustomType". 37 | // 38 | // Be default unrecognized types will be recursively generated by 39 | // traversing their import package (when possible). 40 | TypeMappings map[string]string 41 | 42 | // WithConstants indicates whether to generate types for constants 43 | // ("false" by default). 44 | WithConstants bool 45 | 46 | // WithPackageFunctions indicates whether to generate types 47 | // for package level functions ("false" by default). 48 | WithPackageFunctions bool 49 | 50 | // FieldNameFormatter allows specifying a custom struct field name formatter. 51 | FieldNameFormatter FieldNameFormatterFunc 52 | 53 | // MethodNameFormatter allows specifying a custom method name formatter. 54 | MethodNameFormatter MethodNameFormatterFunc 55 | 56 | // StartModifier usually should be "export" or declare but as of now prevents 57 | // the LSP autocompletion so we keep it empty. 58 | // 59 | // See also: 60 | // https://github.com/microsoft/TypeScript/issues/54330 61 | // https://github.com/microsoft/TypeScript/pull/49644 62 | StartModifier string 63 | 64 | // Indent allow customizing the default indentation (use \t if you want tabs). 65 | Indent string 66 | } 67 | 68 | // Initializes the defaults (if not already) of the current config. 69 | func (c *Config) InitDefaults() { 70 | if c.Indent == "" { 71 | c.Indent = defaultIndent 72 | } 73 | 74 | if c.TypeMappings == nil { 75 | c.TypeMappings = make(map[string]string) 76 | } 77 | 78 | // special case for the unsafe package because it doesn't return its types in pkg.Syntax 79 | if _, ok := c.TypeMappings["unsafe.Pointer"]; !ok { 80 | c.TypeMappings["unsafe.Pointer"] = "number" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /package_generator.go: -------------------------------------------------------------------------------- 1 | package tygoja 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | "strings" 7 | 8 | "golang.org/x/tools/go/packages" 9 | ) 10 | 11 | // PackageGenerator is responsible for generating the code for a single input package. 12 | type PackageGenerator struct { 13 | conf *Config 14 | pkg *packages.Package 15 | types []string 16 | withPkgDoc bool 17 | 18 | generatedTypes map[string]struct{} 19 | unknownTypes map[string]struct{} 20 | imports map[string][]string // path -> []names/aliases 21 | } 22 | 23 | // Generate generates the typings for a single package. 24 | func (g *PackageGenerator) Generate() (string, error) { 25 | s := new(strings.Builder) 26 | 27 | namespace := packageNameFromPath(g.pkg.ID) 28 | 29 | s.WriteString("\n") 30 | 31 | if g.withPkgDoc { 32 | for _, f := range g.pkg.Syntax { 33 | if f.Doc == nil || len(f.Doc.List) == 0 { 34 | continue 35 | } 36 | g.writeCommentGroup(s, f.Doc, 0) 37 | } 38 | } 39 | 40 | g.writeStartModifier(s, 0) 41 | s.WriteString("namespace ") 42 | s.WriteString(namespace) 43 | s.WriteString(" {\n") 44 | 45 | // register the aliased imports within the package namespace 46 | // (see https://www.typescriptlang.org/docs/handbook/namespaces.html#aliases) 47 | loadedAliases := map[string]struct{}{} 48 | for _, file := range g.pkg.Syntax { 49 | for _, imp := range file.Imports { 50 | path := strings.Trim(imp.Path.Value, `"' `) 51 | 52 | pgkName := packageNameFromPath(path) 53 | alias := pgkName 54 | 55 | if imp.Name != nil && imp.Name.Name != "" && imp.Name.Name != "_" { 56 | alias = imp.Name.Name 57 | 58 | if _, ok := loadedAliases[alias]; ok { 59 | continue // already registered 60 | } 61 | 62 | loadedAliases[alias] = struct{}{} 63 | 64 | g.writeIndent(s, 1) 65 | s.WriteString("// @ts-ignore\n") 66 | g.writeIndent(s, 1) 67 | s.WriteString("import ") 68 | s.WriteString(alias) 69 | s.WriteString(" = ") 70 | s.WriteString(pgkName) 71 | s.WriteString("\n") 72 | } 73 | 74 | // register the import to export its package later 75 | if !exists(g.imports[path], alias) { 76 | if g.imports[path] == nil { 77 | g.imports[path] = []string{} 78 | } 79 | g.imports[path] = append(g.imports[path], alias) 80 | } 81 | } 82 | 83 | ast.Inspect(file, func(n ast.Node) bool { 84 | switch x := n.(type) { 85 | case *ast.FuncDecl: // FuncDecl can be package level function or struct method 86 | g.writeFuncDecl(s, x, 1) 87 | return false 88 | case *ast.GenDecl: // GenDecl can be an import, type, var, or const expression 89 | if x.Tok == token.VAR || x.Tok == token.IMPORT { 90 | return false // ignore variables and import statements for now 91 | } 92 | 93 | g.writeGroupDecl(s, x, 1) 94 | return false 95 | } 96 | 97 | return true 98 | }) 99 | } 100 | 101 | s.WriteString("}\n") 102 | 103 | return s.String(), nil 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | (EXP) tygoja 2 | [![GoDoc](https://godoc.org/github.com/pocketbase/tygoja?status.svg)](https://pkg.go.dev/github.com/pocketbase/tygoja) 3 | ====================================================================== 4 | 5 | **tygoja** is a small helper library for generating TypeScript declarations from Go code. 6 | 7 | The generated typings are intended to be used as import helpers to provide [ambient TypeScript declarations](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) (aka. `.d.ts`) for [goja](https://github.com/dop251/goja) bindings. 8 | 9 | > **⚠️ Don't use it directly in production! It is not tagged and may change without notice.** 10 | > 11 | > **It was created to semi-automate the documentation of the goja integration for PocketBase.** 12 | > 13 | > **Use it only as a reference or as a non-critical step in your dev pipeline.** 14 | 15 | **tygoja** is a heavily modified fork of [tygo](https://github.com/gzuidhof/tygo) and extends its scope with: 16 | 17 | - custom field and method names formatters 18 | - types for interfaces (exported and unexported) 19 | - types for exported interface methods 20 | - types for exported struct methods 21 | - types for exported package level functions (_must enable `PackageConfig.WithPackageFunctions`_) 22 | - inheritance declarations for embeded structs (_embedded pointers are treated as values_) 23 | - autoloading all unmapped argument and return types (_when possible_) 24 | - applying the same [goja's rules](https://pkg.go.dev/github.com/dop251/goja#hdr-Nil) when resolving the return types of exported function and methods 25 | - combining multiple packages typings in a single output 26 | - generating all declarations in namespaces with the packages name (both unmapped and mapped) 27 | - preserving comment block new lines 28 | - converting Go comment code blocks to Markdown code blocks 29 | - and others... 30 | 31 | Note that by default the generated typings are not generated with `export` since the intended usage is to map them to your custom goja bindings. 32 | This mapping could be defined in the `Config.Heading` field usually with the `declare` keyword (eg. `declare let someGojaProp: app.Cache`). 33 | 34 | ## Example 35 | 36 | ```go 37 | package main 38 | 39 | import ( 40 | "log" 41 | "os" 42 | 43 | "github.com/pocketbase/tygoja" 44 | ) 45 | 46 | func main() { 47 | gen := tygoja.New(tygoja.Config{ 48 | Packages: map[string][]string{ 49 | "github.com/pocketbase/tygoja/test/a": {"*"}, 50 | "github.com/pocketbase/tygoja/test/b": {"*"}, 51 | "github.com/pocketbase/tygoja/test/c": {"Example2", "Handler"}, 52 | }, 53 | Heading: `declare var $app: c.Handler; // bind other fields `, 54 | WithPackageFunctions: true, 55 | }) 56 | 57 | result, err := gen.Generate() 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | 62 | if err := os.WriteFile("./types.d.ts", []byte(result), 0644); err != nil { 63 | log.Fatal(err) 64 | } 65 | } 66 | ``` 67 | 68 | You can also combine it with [typedoc](https://typedoc.org/) to create HTML/JSON docs from the generated declaration(s). 69 | 70 | See the package `/test` directory for example output. 71 | 72 | For a more detailed example you can also explore the [PocketBase's jsvm plugin](https://github.com/pocketbase/pocketbase/tree/develop/plugins/jsvm/internal/docs). 73 | 74 | 75 | ## Known issues and limitations 76 | 77 | - Multiple versions of the same package may have unexpected declaration since all versions will be under the same namespace. 78 | - For easier generation, it relies on TypeScript declarations merging, meaning that the generated types may not be very compact. 79 | - Package level functions and constants, that are reserved JS identifier, are prefixed with underscore (eg. `_in()`). 80 | -------------------------------------------------------------------------------- /tygoja.go: -------------------------------------------------------------------------------- 1 | package tygoja 2 | 3 | import ( 4 | "fmt" 5 | "path/filepath" 6 | "regexp" 7 | "strings" 8 | 9 | "golang.org/x/tools/go/packages" 10 | ) 11 | 12 | // Tygoja is a generator for one or more input packages, 13 | // responsible for linking them together if necessary. 14 | type Tygoja struct { 15 | conf *Config 16 | 17 | parent *Tygoja 18 | implicitPackages map[string][]string 19 | generatedTypes map[string][]string 20 | generatedPackageDocs map[string]struct{} 21 | } 22 | 23 | // New initializes a new Tygoja generator from the specified config. 24 | func New(config Config) *Tygoja { 25 | config.InitDefaults() 26 | 27 | return &Tygoja{ 28 | conf: &config, 29 | implicitPackages: map[string][]string{}, 30 | generatedTypes: map[string][]string{}, 31 | generatedPackageDocs: map[string]struct{}{}, 32 | } 33 | } 34 | 35 | // Generate executes the generator and produces the related TS files. 36 | func (g *Tygoja) Generate() (string, error) { 37 | // extract config packages 38 | configPackages := make([]string, 0, len(g.conf.Packages)) 39 | for p, types := range g.conf.Packages { 40 | if len(types) == 0 { 41 | continue // no typings 42 | } 43 | configPackages = append(configPackages, p) 44 | } 45 | 46 | // load packages info 47 | pkgs, err := packages.Load(&packages.Config{ 48 | Mode: packages.NeedSyntax | packages.NeedFiles | packages.NeedDeps | packages.NeedImports | packages.NeedTypes, 49 | }, configPackages...) 50 | if err != nil { 51 | return "", err 52 | } 53 | 54 | var s strings.Builder 55 | 56 | // Heading 57 | if g.parent == nil { 58 | s.WriteString("// GENERATED CODE - DO NOT MODIFY BY HAND\n") 59 | 60 | if g.conf.Heading != "" { 61 | s.WriteString(g.conf.Heading) 62 | } 63 | 64 | // write base types 65 | // --- 66 | s.WriteString("type ") 67 | s.WriteString(BaseTypeDict) 68 | s.WriteString(" = { [key:string | number | symbol]: any; }\n") 69 | 70 | s.WriteString("type ") 71 | s.WriteString(BaseTypeAny) 72 | s.WriteString(" = any\n") 73 | // --- 74 | } 75 | 76 | for i, pkg := range pkgs { 77 | if len(pkg.Errors) > 0 { 78 | return "", fmt.Errorf("%+v", pkg.Errors) 79 | } 80 | 81 | if len(pkg.GoFiles) == 0 { 82 | return "", fmt.Errorf("no input go files for package index %d", i) 83 | } 84 | 85 | if len(g.conf.Packages[pkg.ID]) == 0 { 86 | // ignore the package as it has no typings 87 | continue 88 | } 89 | 90 | pkgGen := &PackageGenerator{ 91 | conf: g.conf, 92 | pkg: pkg, 93 | types: g.conf.Packages[pkg.ID], 94 | withPkgDoc: !g.isPackageDocGenerated(pkg.ID), 95 | generatedTypes: map[string]struct{}{}, 96 | unknownTypes: map[string]struct{}{}, 97 | imports: map[string][]string{}, 98 | } 99 | 100 | code, err := pkgGen.Generate() 101 | if err != nil { 102 | return "", err 103 | } 104 | 105 | g.generatedPackageDocs[pkg.ID] = struct{}{} 106 | 107 | for t := range pkgGen.generatedTypes { 108 | g.generatedTypes[pkg.ID] = append(g.generatedTypes[pkg.ID], t) 109 | } 110 | 111 | for t := range pkgGen.unknownTypes { 112 | parts := strings.Split(t, ".") 113 | var tPkg string 114 | var tName string 115 | 116 | if len(parts) == 0 { 117 | continue 118 | } 119 | 120 | if len(parts) == 2 { 121 | // type from external package 122 | tPkg = parts[0] 123 | tName = parts[1] 124 | } else { 125 | // unexported type from the current package 126 | tName = parts[0] 127 | 128 | // already mapped for export 129 | if pkgGen.isTypeAllowed(tName) { 130 | continue 131 | } 132 | 133 | tPkg = packageNameFromPath(pkg.ID) 134 | 135 | // add to self import later 136 | pkgGen.imports[pkg.ID] = []string{tPkg} 137 | } 138 | 139 | for p, aliases := range pkgGen.imports { 140 | for _, alias := range aliases { 141 | if tName != "" && alias == tPkg && !g.isTypeGenerated(p, tName) && !exists(g.implicitPackages[p], tName) { 142 | if g.implicitPackages[p] == nil { 143 | g.implicitPackages[p] = []string{} 144 | } 145 | g.implicitPackages[p] = append(g.implicitPackages[p], tName) 146 | break 147 | } 148 | } 149 | } 150 | } 151 | 152 | s.WriteString(code) 153 | } 154 | 155 | // recursively try to generate the found unknown types 156 | if len(g.implicitPackages) > 0 { 157 | subConfig := *g.conf 158 | subConfig.Heading = "" 159 | if (subConfig.TypeMappings) == nil { 160 | subConfig.TypeMappings = map[string]string{} 161 | } 162 | 163 | // extract the nonempty package definitions 164 | subConfig.Packages = make(map[string][]string, len(g.implicitPackages)) 165 | for p, types := range g.implicitPackages { 166 | if len(types) == 0 { 167 | continue 168 | } 169 | subConfig.Packages[p] = types 170 | } 171 | 172 | subGenerator := New(subConfig) 173 | subGenerator.parent = g 174 | subResult, err := subGenerator.Generate() 175 | if err != nil { 176 | return "", err 177 | } 178 | 179 | s.WriteString(subResult) 180 | } 181 | 182 | return s.String(), nil 183 | } 184 | 185 | func (g *Tygoja) isPackageDocGenerated(pkgId string) bool { 186 | _, ok := g.generatedPackageDocs[pkgId] 187 | if ok { 188 | return true 189 | } 190 | 191 | if g.parent != nil { 192 | return g.parent.isPackageDocGenerated(pkgId) 193 | } 194 | 195 | return false 196 | } 197 | 198 | func (g *Tygoja) isTypeGenerated(pkg string, name string) bool { 199 | if g.parent != nil && g.parent.isTypeGenerated(pkg, name) { 200 | return true 201 | } 202 | 203 | if len(g.generatedTypes[pkg]) == 0 { 204 | return false 205 | } 206 | 207 | for _, t := range g.generatedTypes[pkg] { 208 | if t == name { 209 | return true 210 | } 211 | } 212 | 213 | return false 214 | } 215 | 216 | // isTypeAllowed checks whether the provided type name is allowed by the generator "types". 217 | func (g *PackageGenerator) isTypeAllowed(name string) bool { 218 | name = strings.TrimSpace(name) 219 | 220 | if name == "" { 221 | return false 222 | } 223 | 224 | for _, t := range g.types { 225 | if t == name || t == "*" { 226 | return true 227 | } 228 | } 229 | 230 | return false 231 | } 232 | 233 | func (g *PackageGenerator) markTypeAsGenerated(t string) { 234 | g.generatedTypes[t] = struct{}{} 235 | } 236 | 237 | var versionRegex = regexp.MustCompile(`^v\d+$`) 238 | 239 | // packageNameFromPath extracts and normalizes the imported package identifier. 240 | // 241 | // For example: 242 | // 243 | // "github.com/labstack/echo/v5" -> "echo" 244 | // "github.com/go-ozzo/ozzo-validation/v4" -> "ozzo_validation" 245 | func packageNameFromPath(path string) string { 246 | name := filepath.Base(strings.Trim(path, `"' `)) 247 | 248 | if versionRegex.MatchString(name) { 249 | name = filepath.Base(filepath.Dir(path)) 250 | } 251 | 252 | return strings.ReplaceAll(name, "-", "_") 253 | } 254 | 255 | // exists checks if search exists in list. 256 | func exists[T comparable](list []T, search T) bool { 257 | for _, v := range list { 258 | if v == search { 259 | return true 260 | } 261 | } 262 | 263 | return false 264 | } 265 | -------------------------------------------------------------------------------- /test/htmldocs/types/_TygojaAny.html: -------------------------------------------------------------------------------- 1 | _TygojaAny | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Type alias _TygojaAny

18 |
_TygojaAny: any
21 |
22 | 36 |
46 |
47 |

Generated using TypeDoc

48 |
-------------------------------------------------------------------------------- /test/htmldocs/functions/_app.html: -------------------------------------------------------------------------------- 1 | $app | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Function $app

18 |
19 |
    20 | 21 |
  • 22 |

    Returns string

25 |
26 | 40 |
50 |
51 |

Generated using TypeDoc

52 |
-------------------------------------------------------------------------------- /test/htmldocs/types/_TygojaDict.html: -------------------------------------------------------------------------------- 1 | _TygojaDict | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Type alias _TygojaDict

18 |
_TygojaDict: {
    [key: string | number | symbol]: any;
}
19 |
20 |

Type declaration

21 |
    22 |
  • 23 |
    [key: string | number | symbol]: any
26 |
27 | 41 |
51 |
52 |

Generated using TypeDoc

53 |
-------------------------------------------------------------------------------- /test/htmldocs/modules.html: -------------------------------------------------------------------------------- 1 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 |

Documentation

15 |
16 |
17 |

Index

18 |
19 |

Namespaces

20 |
a 21 | b 22 | c 23 | time 24 |
25 |
26 |

Type Aliases

27 |
30 |
31 |

Functions

32 |
$app 33 |
34 |
35 | 49 |
59 |
60 |

Generated using TypeDoc

61 |
-------------------------------------------------------------------------------- /test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "devDependencies": { 8 | "typedoc": "^0.24.8" 9 | } 10 | }, 11 | "node_modules/ansi-sequence-parser": { 12 | "version": "1.1.0", 13 | "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", 14 | "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", 15 | "dev": true 16 | }, 17 | "node_modules/balanced-match": { 18 | "version": "1.0.2", 19 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 20 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 21 | "dev": true 22 | }, 23 | "node_modules/brace-expansion": { 24 | "version": "2.0.1", 25 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 26 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 27 | "dev": true, 28 | "dependencies": { 29 | "balanced-match": "^1.0.0" 30 | } 31 | }, 32 | "node_modules/jsonc-parser": { 33 | "version": "3.2.0", 34 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", 35 | "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", 36 | "dev": true 37 | }, 38 | "node_modules/lunr": { 39 | "version": "2.3.9", 40 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", 41 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", 42 | "dev": true 43 | }, 44 | "node_modules/marked": { 45 | "version": "4.3.0", 46 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", 47 | "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", 48 | "dev": true, 49 | "bin": { 50 | "marked": "bin/marked.js" 51 | }, 52 | "engines": { 53 | "node": ">= 12" 54 | } 55 | }, 56 | "node_modules/minimatch": { 57 | "version": "9.0.1", 58 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", 59 | "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", 60 | "dev": true, 61 | "dependencies": { 62 | "brace-expansion": "^2.0.1" 63 | }, 64 | "engines": { 65 | "node": ">=16 || 14 >=14.17" 66 | }, 67 | "funding": { 68 | "url": "https://github.com/sponsors/isaacs" 69 | } 70 | }, 71 | "node_modules/shiki": { 72 | "version": "0.14.2", 73 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz", 74 | "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==", 75 | "dev": true, 76 | "dependencies": { 77 | "ansi-sequence-parser": "^1.1.0", 78 | "jsonc-parser": "^3.2.0", 79 | "vscode-oniguruma": "^1.7.0", 80 | "vscode-textmate": "^8.0.0" 81 | } 82 | }, 83 | "node_modules/typedoc": { 84 | "version": "0.24.8", 85 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", 86 | "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", 87 | "dev": true, 88 | "dependencies": { 89 | "lunr": "^2.3.9", 90 | "marked": "^4.3.0", 91 | "minimatch": "^9.0.0", 92 | "shiki": "^0.14.1" 93 | }, 94 | "bin": { 95 | "typedoc": "bin/typedoc" 96 | }, 97 | "engines": { 98 | "node": ">= 14.14" 99 | }, 100 | "peerDependencies": { 101 | "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" 102 | } 103 | }, 104 | "node_modules/typedoc-twilio-theme": { 105 | "version": "1.0.1", 106 | "resolved": "https://registry.npmjs.org/typedoc-twilio-theme/-/typedoc-twilio-theme-1.0.1.tgz", 107 | "integrity": "sha512-9cT7fli3+1x0CcQvavenemzjpEh9jOG93Dr9j8vqmI6BBjBA22cUsAVoYYSwu0E/nOJOKWxYqtfM4t2qHi8QMA==", 108 | "dev": true, 109 | "engines": { 110 | "node": ">= 4" 111 | } 112 | }, 113 | "node_modules/typescript": { 114 | "version": "5.1.3", 115 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", 116 | "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", 117 | "dev": true, 118 | "peer": true, 119 | "bin": { 120 | "tsc": "bin/tsc", 121 | "tsserver": "bin/tsserver" 122 | }, 123 | "engines": { 124 | "node": ">=14.17" 125 | } 126 | }, 127 | "node_modules/vscode-oniguruma": { 128 | "version": "1.7.0", 129 | "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", 130 | "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", 131 | "dev": true 132 | }, 133 | "node_modules/vscode-textmate": { 134 | "version": "8.0.0", 135 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", 136 | "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", 137 | "dev": true 138 | } 139 | }, 140 | "dependencies": { 141 | "ansi-sequence-parser": { 142 | "version": "1.1.0", 143 | "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", 144 | "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", 145 | "dev": true 146 | }, 147 | "balanced-match": { 148 | "version": "1.0.2", 149 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 150 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 151 | "dev": true 152 | }, 153 | "brace-expansion": { 154 | "version": "2.0.1", 155 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 156 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 157 | "dev": true, 158 | "requires": { 159 | "balanced-match": "^1.0.0" 160 | } 161 | }, 162 | "jsonc-parser": { 163 | "version": "3.2.0", 164 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", 165 | "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", 166 | "dev": true 167 | }, 168 | "lunr": { 169 | "version": "2.3.9", 170 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", 171 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", 172 | "dev": true 173 | }, 174 | "marked": { 175 | "version": "4.3.0", 176 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", 177 | "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", 178 | "dev": true 179 | }, 180 | "minimatch": { 181 | "version": "9.0.1", 182 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", 183 | "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", 184 | "dev": true, 185 | "requires": { 186 | "brace-expansion": "^2.0.1" 187 | } 188 | }, 189 | "shiki": { 190 | "version": "0.14.2", 191 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz", 192 | "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==", 193 | "dev": true, 194 | "requires": { 195 | "ansi-sequence-parser": "^1.1.0", 196 | "jsonc-parser": "^3.2.0", 197 | "vscode-oniguruma": "^1.7.0", 198 | "vscode-textmate": "^8.0.0" 199 | } 200 | }, 201 | "typedoc": { 202 | "version": "0.24.8", 203 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", 204 | "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", 205 | "dev": true, 206 | "requires": { 207 | "lunr": "^2.3.9", 208 | "marked": "^4.3.0", 209 | "minimatch": "^9.0.0", 210 | "shiki": "^0.14.1" 211 | } 212 | }, 213 | "typedoc-twilio-theme": { 214 | "version": "https://registry.npmjs.org/typedoc-twilio-theme/-/typedoc-twilio-theme-1.0.1.tgz", 215 | "integrity": "sha512-9cT7fli3+1x0CcQvavenemzjpEh9jOG93Dr9j8vqmI6BBjBA22cUsAVoYYSwu0E/nOJOKWxYqtfM4t2qHi8QMA==", 216 | "dev": true 217 | }, 218 | "typescript": { 219 | "version": "5.1.3", 220 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", 221 | "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", 222 | "dev": true, 223 | "peer": true 224 | }, 225 | "vscode-oniguruma": { 226 | "version": "1.7.0", 227 | "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", 228 | "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", 229 | "dev": true 230 | }, 231 | "vscode-textmate": { 232 | "version": "8.0.0", 233 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", 234 | "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", 235 | "dev": true 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /test/htmldocs/modules/c.html: -------------------------------------------------------------------------------- 1 | c | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Namespace c

21 |
22 |
23 |

Index

24 |
25 |

Interfaces

26 |
Example1 27 | Example2 28 | Handler 29 | Raw 30 |
31 |
32 | 46 |
63 |
64 |

Generated using TypeDoc

65 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/a.Empty.html: -------------------------------------------------------------------------------- 1 | Empty | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Empty

19 |
20 |

Hierarchy

21 |
    22 |
  • Empty
23 |
24 |

Indexable

25 |
[key: string]: any
28 |
29 | 43 |
65 |
66 |

Generated using TypeDoc

67 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/c.Handler.html: -------------------------------------------------------------------------------- 1 | Handler | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Handler

19 |
20 |

func type comment

21 |
22 |
23 |
24 |

Hierarchy

25 |
    26 |
  • Handler
27 |
28 |
    29 | 30 |
  • 31 |

    Returns string

34 |
35 | 49 |
66 |
67 |

Generated using TypeDoc

68 |
-------------------------------------------------------------------------------- /test/htmldocs/types/a._subOLPog.html: -------------------------------------------------------------------------------- 1 | _subOLPog | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Type alias _subOLPog

19 |
_subOLPog: unexported & structA
20 |

structB comment

21 |
22 |
25 |
26 | 40 |
62 |
63 |

Generated using TypeDoc

64 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func1.html: -------------------------------------------------------------------------------- 1 | Func1 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func1

19 |
20 |

Hierarchy

21 |
    22 |
  • Func1
23 |
24 |
    25 | 26 |
  • 27 |

    single comment

    28 |
    29 |

    Returns void

    30 |
33 |
34 | 48 |
70 |
71 |

Generated using TypeDoc

72 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func7.html: -------------------------------------------------------------------------------- 1 | Func7 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func7

19 |
20 |

Hierarchy

21 |
    22 |
  • Func7
23 |
24 |
    25 | 26 |
  • 27 |

    function with named return values

    28 |
    29 |

    Returns [number, string]

    30 |
33 |
34 | 48 |
70 |
71 |

Generated using TypeDoc

72 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func8.html: -------------------------------------------------------------------------------- 1 | Func8 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func8

19 |
20 |

Hierarchy

21 |
    22 |
  • Func8
23 |
24 |
    25 | 26 |
  • 27 |

    function with shortened return values

    28 |
    29 |

    Returns [string, string]

    30 |
33 |
34 | 48 |
70 |
71 |

Generated using TypeDoc

72 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func2.html: -------------------------------------------------------------------------------- 1 | Func2 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func2<T>

19 |
20 |

Type Parameters

21 |
    22 |
  • 23 |

    T

24 |
25 |

Hierarchy

26 |
    27 |
  • Func2
28 |
29 |
    30 | 31 |
  • 32 |

    multi 33 | line 34 | comment

    35 |
    36 |
    37 |

    Parameters

    38 |
      39 |
    • 40 |
      arg1: number
    41 |

    Returns T

    42 |
45 |
46 | 60 |
82 |
83 |

Generated using TypeDoc

84 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func9.html: -------------------------------------------------------------------------------- 1 | Func9 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func9

19 |
20 |

Hierarchy

21 |
    22 |
  • Func9
23 |
24 |
    25 | 26 |
  • 27 |

    function with named and shortened return values

    28 |
    29 |

    Returns [number, string, string]

    30 |
33 |
34 | 48 |
70 |
71 |

Generated using TypeDoc

72 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func4.html: -------------------------------------------------------------------------------- 1 | Func4 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func4

19 |
20 |

Hierarchy

21 |
    22 |
  • Func4
23 |
24 |
    25 | 26 |
  • 27 |

    function with ommited argument types

    28 |
    29 |
    30 |

    Parameters

    31 |
      32 |
    • 33 |
      arg0: string
    • 34 |
    • 35 |
      arg1: number
    • 36 |
    • 37 |
      arg2: number
    38 |

    Returns void

    39 |
42 |
43 | 57 |
79 |
80 |

Generated using TypeDoc

81 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/b.Func5.html: -------------------------------------------------------------------------------- 1 | Func5 | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Func5

19 |
20 |

Hierarchy

21 |
    22 |
  • Func5
23 |
24 |
    25 | 26 |
  • 27 |

    function with reserved argument name and variadic type

    28 |
    29 |
    30 |

    Parameters

    31 |
      32 |
    • 33 |
      _arg00: string
    • 34 |
    • 35 |
      Rest ...optional: string[]
    36 |

    Returns void

    37 |
40 |
41 | 55 |
77 |
78 |

Generated using TypeDoc

79 |
-------------------------------------------------------------------------------- /test/htmldocs/interfaces/a.Handler.html: -------------------------------------------------------------------------------- 1 | Handler | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 18 |

Interface Handler<T>

19 |
20 |

multi 21 | line 22 | comment

23 |
24 |
25 |
26 |

Type Parameters

27 |
    28 |
  • 29 |

    T

30 |
31 |

Hierarchy

32 |
    33 |
  • Handler
34 |
35 |
    36 | 37 |
  • 38 |

    Returns [T, number]

41 |
42 | 56 |
78 |
79 |

Generated using TypeDoc

80 |
-------------------------------------------------------------------------------- /test/htmldocs/modules/b.html: -------------------------------------------------------------------------------- 1 | b | Documentation
2 |
3 | 10 |
11 |
12 |
13 |
14 | 17 |

Namespace b

18 |
19 |

package b

20 |
21 |
24 |
25 |
26 |

Index

27 |
28 |

Interfaces

29 |
Func1 30 | Func2 31 | Func3 32 | Func4 33 | Func5 34 | Func6 35 | Func7 36 | Func8 37 | Func9 38 |
39 |
40 | 54 |
76 |
77 |

Generated using TypeDoc

78 |
--------------------------------------------------------------------------------