Skip to content
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

Documentation on mkunion and storage and resiliency #125

Merged
merged 56 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
27f5058
docs: mention on order of running mkunion watch and go generate
widmogrod Jun 2, 2024
30a2724
docs: fix how typescript code is embedded
widmogrod Jun 2, 2024
f204395
example: external calls now support context
widmogrod Jun 2, 2024
f366538
example: propagate context in order example
widmogrod Jun 2, 2024
b9308b1
cmd/mkunion: check file extension in watch process
widmogrod Jun 4, 2024
a03e90c
x/shape: change toopenaifunction.go signature
widmogrod Jun 4, 2024
c1fb903
my-app: update deps to make it work
widmogrod Jun 4, 2024
9e03d78
my-app: PaginatedTable support OR
widmogrod Jun 8, 2024
0cab1e4
my-app: example how to filter by function name
widmogrod Jun 8, 2024
e60bb51
my-app: regenerate typescript types
widmogrod Jun 9, 2024
a220939
my-app: fix eslint in PaginatedTable
widmogrod Jun 9, 2024
6e83fc2
my-app: workflow to string from runID
widmogrod Jun 9, 2024
bb1d164
x/workflow: workflow to string can render errors
widmogrod Jun 9, 2024
46665d6
x/taskqueue: update test due to x/workflow refactor
widmogrod Jun 9, 2024
cac1e2f
my-app: add context support when applicable, and new endpoint workflo…
widmogrod Jun 9, 2024
687d1bf
my-app: rerender typescript types
widmogrod Jun 9, 2024
ab224a8
x/shape: introduce missing init shape
widmogrod Jun 15, 2024
b9a00dd
x/storage/predicate: fix error name
widmogrod Jun 15, 2024
2bf5adf
x/storage/predicate: WherePredicate now support can have shape defini…
widmogrod Jun 15, 2024
1a43b87
x/storage: update predicate.MustWhere signature
widmogrod Jun 15, 2024
cd15d8c
x/storage: remove comment
widmogrod Jun 15, 2024
8282a90
docs: update roadmap
widmogrod Jun 15, 2024
5c7f275
x/storage: update predicate.MustWhere signature
widmogrod Jun 15, 2024
fcc7a32
x/schema: introduce missing init shape
widmogrod Jun 15, 2024
a3785f3
x/schema: TypedLocation now allow to get ShapeDef
widmogrod Jun 15, 2024
c5c909f
x/shape: introduce missing init shape
widmogrod Jun 15, 2024
71a74a6
x/shape: add new tests to check how recursion schema works on even mo…
widmogrod Jun 15, 2024
ef15331
x/projection: update predicate.MustWhere signature
widmogrod Jun 15, 2024
663ec8f
x/storage: propagate schema definition through layers, for more accur…
widmogrod Jun 15, 2024
1991ba5
x/taskqueue: add logging and predicate.MustWhere signature change
widmogrod Jun 15, 2024
4d6754e
my-app: task queue for background error fixing
widmogrod Jun 15, 2024
6e913c4
x/schema: looking for shapes returns found flag, to distinguish from …
widmogrod Jun 15, 2024
d2f3001
x/storage/predicate: distinguish found from null
widmogrod Jun 15, 2024
8e50b31
x/storage/predicate: Where allows for options that disable extra para…
widmogrod Jun 15, 2024
418cc1b
x/taskqueue: disables extra params checks in predicates
widmogrod Jun 15, 2024
a7fb3ef
my-app: introduce timeout checking process for workflows with callbacks
widmogrod Jun 15, 2024
c7b1ada
my-app: server use timeout taskqueue
widmogrod Jun 15, 2024
7555288
x/workflow: new ExpireAsync command, and improvements
widmogrod Jun 15, 2024
695e3f4
x/machine: reports proper line in test output
widmogrod Jun 15, 2024
eb5e972
x/storage: update code to respect GetSchema functions signature change
widmogrod Jun 15, 2024
38e3f94
my-app: regenereate typescript
widmogrod Jun 15, 2024
590d4ba
my-app: fix callFun directly
widmogrod Jun 18, 2024
609295f
x/schema: more robust location implementation
widmogrod Jun 30, 2024
7dd7fcc
x/predicate: remove unused function
widmogrod Jun 30, 2024
a31841f
x/storage: typed location us used with encoded info
widmogrod Jul 13, 2024
f903a7b
x/workflow: introduce explicit problem codes
widmogrod Jul 13, 2024
015e9a1
x/schema: improve how $type is handled with TypedLocation
widmogrod Jul 13, 2024
4d0dea7
my-app: generate typescript
widmogrod Jul 13, 2024
9d42cda
my-app: fix Errorf params
widmogrod Jul 13, 2024
12e7fec
x/generator: refactor mkmatch generation
widmogrod Jul 13, 2024
5362a13
x/shape: now collects ast.Nodes associated with go:tag to allow exten…
widmogrod Jul 13, 2024
c75ecdc
cmd/mkunion: now supports mkmatch tag
widmogrod Jul 13, 2024
968fd08
*: introduce mkmatch tag
widmogrod Jul 13, 2024
751ffdb
x/generator: mkmatch with has bigger tolerance
widmogrod Jul 13, 2024
0eb1df7
mkmatch: make allow to set custom name, otherwise use interface name
widmogrod Jul 13, 2024
07f70cd
docs: update roadmap
widmogrod Jul 13, 2024
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
115 changes: 55 additions & 60 deletions cmd/mkunion/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,54 +90,6 @@ func main() {
return nil
},
Commands: []*cli.Command{
{
Name: "match",
Description: "Generate custom pattern matching function",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Required: true,
},
},
Action: func(c *cli.Context) error {
cwd, _ := syscall.Getwd()
sourceName := path.Base(os.Getenv("GOFILE"))
sourcePath := path.Join(cwd, sourceName)

baseName := strings.TrimSuffix(sourceName, path.Ext(sourceName))

// file name without extension
inferred, err := generators.InferDeriveFuncMatchFromFile(sourcePath)
if err != nil {
return err
}

specName := c.String("name")
spec, err := inferred.MatchSpec(specName)
if err != nil {
return err
}

derived := generators.DeriveFuncMatchGenerator{
Header: "// Code generated by mkunion. DO NOT EDIT.",
PackageName: inferred.PackageName,
MatchSpec: *spec,
}

b, err := derived.Generate()
if err != nil {
return err
}
err = os.WriteFile(path.Join(
cwd,
baseName+"_match_"+strings.ToLower(derived.MatchSpec.Name)+".go"), b, 0644)
if err != nil {
return fmt.Errorf("failed to write %s for %s in %s: %w", "gen", derived.MatchSpec.Name, sourcePath, err)
}

return nil
},
},
{
Name: "shape-export",
Description: "Generate typescript types from golang types, and enable end-to-end type safety.",
Expand Down Expand Up @@ -256,33 +208,41 @@ func main() {
return
}

// is .go file?
if filepath.Ext(event.Name) != ".go" {
continue
}

if event.Op&fsnotify.Chmod == fsnotify.Chmod {
continue
}

// extract path name from event.Name
pathName := strings.Trim(event.Name, `"`)

if event.Op&fsnotify.Remove == fsnotify.Remove {
// if the file was removed, regenerate type registry
savedFiles, err := GenerateTypeRegistryForDir([]string{filepath.Dir(event.Name)})
dir := filepath.Dir(event.Name)

backLevel := log.GetLevel()
log.SetLevel(log.ErrorLevel)
savedFiles, err := GenerateTypeRegistryForDir([]string{dir})
log.SetLevel(backLevel)

if err != nil {
log.Warnf("failed to generate type registry for %s: %s", filepath.Dir(event.Name), err)
log.Warnf("failed to generate type registry for %s: %s", dir, err)
continue
}

for _, x := range savedFiles {
log.Infof("re-generated:\t%s", x)

justGenerated.Store(x, true)
}
}

// is .go file?
if filepath.Ext(event.Name) != ".go" {
// and, since file is deleted, skip the rest
continue
}

// extract path name from event.Name
pathName := strings.Trim(event.Name, `"`)

// if the file was generated by watch process, skip it
if _, ok := justGenerated.Load(pathName); ok {
// but to prevent removing it to fast and resulting in infinit-generation loop
Expand Down Expand Up @@ -532,7 +492,6 @@ func GenerateMain(sourcePaths []string, typeRegistry bool) ([]string, error) {
if err != nil {
return savedFiles, fmt.Errorf("failed generating union in %s: %w", sourcePath, err)
}

savedFile, err := SaveFile(contents, sourcePath, "union_gen")
if err != nil {
return savedFiles, fmt.Errorf("failed saving union in %s: %w", sourcePath, err)
Expand All @@ -545,7 +504,6 @@ func GenerateMain(sourcePaths []string, typeRegistry bool) ([]string, error) {
if err != nil {
return savedFiles, fmt.Errorf("failed generating serde in %s: %w", sourcePath, err)
}

savedFile, err = SaveFile(contents, sourcePath, "serde_gen")
if err != nil {
return savedFiles, fmt.Errorf("failed saving serde in %s: %w", sourcePath, err)
Expand All @@ -558,12 +516,22 @@ func GenerateMain(sourcePaths []string, typeRegistry bool) ([]string, error) {
if err != nil {
return savedFiles, fmt.Errorf("failed generating shape in %s: %w", sourcePath, err)
}

savedFile, err = SaveFile(contents, sourcePath, "shape_gen")
if err != nil {
return savedFiles, fmt.Errorf("failed saving shape in %s: %w", sourcePath, err)
}
if len(savedFile) > 0 {
savedFiles = append(savedFiles, savedFile)
}

contents, err = GenerateMatch(inferred)
if err != nil {
return savedFiles, fmt.Errorf("failed generating match in %s: %w", sourcePath, err)
}
savedFile, err = SaveFile(contents, sourcePath, "match_gen")
if err != nil {
return savedFiles, fmt.Errorf("failed saving match in %s: %w", sourcePath, err)
}
if len(savedFile) > 0 {
savedFiles = append(savedFiles, savedFile)
}
Expand Down Expand Up @@ -956,3 +924,30 @@ func GenerateTypeRegistry(inferred *shape.IndexedTypeWalker) (bytes.Buffer, erro

return contents, nil
}

func GenerateMatch(inferred *shape.InferredInfo) (bytes.Buffer, error) {
result := bytes.Buffer{}

match := generators.NewMkMatchTaggedNodeVisitor()
match.FromInferredInfo(inferred)

specs := match.Specs()
if len(specs) == 0 {
return result, nil
}

derived := generators.MkMatchGenerator{
Header: "// Code generated by mkunion. DO NOT EDIT.",
PackageName: inferred.PackageName(),
MatchSpecs: specs,
}

b, err := derived.Generate()

if err != nil {
return result, fmt.Errorf("GenerateMatch: failed to generate match: %w", err)
}

result.Write(b)
return result, nil
}
2 changes: 1 addition & 1 deletion docs/examples/type_script.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ title: End-to-End types between Go and TypeScript
TODO description of generating TypeScript Definitions from using MkUnion

```go title="example/my-app/server.go"
--8<-- "example/my-app/server.go:37:55"
--8<-- "example/my-app/server.go:34:55"
```
6 changes: 6 additions & 0 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ Alternatively you can run `mkunion` command directly
mkunion -i example/vehicle.go
```


#### What order you should run `mkunion watch` and `go generate`?
First run `mkunion watch ./...` to generate union types, and then run `go generate ./...` to generate code that uses union types.

I found that this order works best, especially with extension like `moq` that will fail to generate mocks when an type is not defined, which is the case for union types, unit you run `mkunion watch`.

### Match over union type
When you run `mkunion` command, it will generate file alongside your original file with `union_gen.go` suffix (example [vehicle_union_gen.go](https://github.com/widmogrod/mkunion/tree/main/example/vehicle_union_gen.go))

Expand Down
3 changes: 3 additions & 0 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

- [ ] **docs**: document simple state machine and how to use `mkunion` for it
- [x] **feature**: `mkunion watch ./...` command that watches for changes in files and runs faster than `go generate ./...`
- [x] **feature**: `go:tag mkmatch` to generate pattern matching functions
- [ ] **docs**: document how to write custom pattern matching functions
- [ ] **docs**: document other packages in `x/` directory
- [ ] **docs**: document typescript types generation and end-to-end typs concepts (from backend to frontend)
- [ ] **feature**: expose functions to extract `go:tag` metadata
Expand All @@ -14,3 +16,4 @@
- [ ] **prototype**: http & gRPC client for end-to-end types.
- [ ] **experiment**: allow to derive behaviour for types, like derive(Map), would generated union type with Map() method
- [ ] **experiment**: consider adding explicit discriminator type names like `example.Branch[int]` instead of `example.Branch`. This may complicate TypeScript codegen but it could increase end-to-end type safety.
- [ ] **refactor**: `x/storage` instead of generic, leverage schema information to remove lookup of schemas (overhead), eventually generate storage code
Loading