Skip to content
151 changes: 151 additions & 0 deletions .github/prompts/migration.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Task

Convert the selected Java source into idiomatic Go **with minimal semantic drift**.

- Map packages to directories and package names.
- Map classes (including abstract) and their fields/methods to Go **interface** and **unexported implementation structs**.
- Preserve logic while adapting to Go naming, encapsulation and error handling.
- Keep diffs focused: one Java file -> one Go file (small support code if strictly necessary).

## Inputs

- Java file(s) to convert.
- Any related types the file depends on.
- Package path target within the Go module.

## Outputs

- A new Go file with idiomatic code.

## Package & File Mapping

1. **One-to-one element mapping**
- **Files**: Map each Java source file `<Name>.java` to to one go file, named `lowercase-with-dashes.go` (e.g., `FooBar.java` -> `foo-bar.go`). Be consistent within the package.
- **Classes/Interfaces**: For each Java class or interface define a **Go interface** named after the Java type (exported) and an **unexported implementation struct**.
- **Methods**: Map each java method to a Go method or function. For overloads, pick distinct names (e.g., `Advance`, `AdvanceN`).

2. **Package structure**
- Java: `package com.example.foo.something;`
- Go: directory `foo/something` with `package something` in the file.

## Types & Encapsulation

### Classes -> Interface + Impl Struct

- Define an **interface** named exactly after the Java class, e.g. `Foo`.
- Define a constructor `NewFoo(...) Foo` returning the interface.
- Define an **unexported** struct `fooImpl` implements the interface. Prefer composition/embedding for reuse.

### Fields -> Struct Fields

- Private/encapsulated state lives in unexported struct fields (e.g., `bar int`).
- Provide getters/setters as interface methods only if the Java API requires them to be public. Avoid exporting fields directly unless they are immutable configuration.

### Constructors

For each Java public constructor:

```go
func NewFoo(params) Foo {
return &fooImpl{/* initialize fields */}
}
```

- If multiple Java constructors exist, use either distinct names (`NewFooWithParams`) **or** the functional options pattern for optional params (avoid overloading).

### Methods & Receivers

- **Non-mutating** -> value receiver if the struct is small and the method is read-only.
- **Mutating** -> pointer receiver.
- Prefer returning `(T, error)` over panicking; translate Java exceptions to `error` values when they cross API boundaries.

### Abstract classes

```go
type Foo interface {
// abstract methods + requires accessors
}

type fooBase struct {/* shared fields */}

func (b fooBase) GetX() T { return b.x }

type fooImpl struct {
fooBase
}
func NewFoo(params) Foo {
return &fooImpl{
fooBase: fooBase{/* initialize shared fields */},
}
}
```

### Method overloading

Java:

```java
void advance();
void advance(int n);
```

Go:

```go
func (r *readerImpl) Advance() {}
func (r *readerImpl) AdvanceN(n int) {}
```

### Equality / Hashing

- If Java only overrides `equals()`/`hashCode()`, in Go prefer:
- Use direct `==` for comparable structs; or
- Provide an explicit **lookup key**:

```go
type FooLookupKey struct { Bar int; Baz string }
func (f *fooImpl) FooLookupKey() FooLookupKey { return FooLookupKey{f.bar, f.baz} }
```

## Naming & Comments

- **Packages:** short, lowercase, single word (`something`).
- **Exports:** capitalize to export. Keep names concise and avoid stutter (prefer `something.Reader` with type name `Reader`).

## Error Handling

- Always return `(T, error)` for fallible operations. Don't use `panic` for normal control flow.
- Wrap lower-level errors with context using `fmt.Errorf("op: %w", err)` so callers can use `errors.Is/As`.
- Match errors with `errors.Is` (sentinels) or `errors.As` (typed errors with additional context).

### Java exceptions -> Go typed errors

- Define Java-specific exceptions as typed errros in `common/errors/errors.go` (package `errors`).

```go
package errors

import "fmt"

type IndexOutOfBoundsError struct {
index int
length int
}

func (e IndexOutOfBoundsError) Error() string {
return fmt.Sprintf("Index %d out of bounds for length %d", e.index, e.length)
}

func (e IndexOutOfBoundsError) GetIndex() int { return e.index }
func (e IndexOutOfBoundsError) GetLength() int { return e.length }
```

## Generics

- Map Java generics to Go generics when needed.

## Guardrails & Non goals

- **Do no** add file headers or license comments.
- **Do not** introduce new public APIs unless requires by the Java surface.
- **Do not** add comments unless the Java source has them.
63 changes: 63 additions & 0 deletions common/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package errors

import "fmt"

type IndexOutOfBoundsError struct {
index int
length int
}

func (e IndexOutOfBoundsError) Error() string {
return fmt.Sprintf("Index %d out of bounds for length %d", e.index, e.length)
}

func (e IndexOutOfBoundsError) GetIndex() int {
return e.index
}

func (e IndexOutOfBoundsError) GetLength() int {
return e.length
}

func NewIndexOutOfBoundsError(index, length int) *IndexOutOfBoundsError {
return &IndexOutOfBoundsError{
index: index,
length: length,
}
}

type IllegalArgumentError struct {
argument any
}

func (e IllegalArgumentError) Error() string {
return fmt.Sprintf("Illegal argument: %v", e.argument)
}

func (e IllegalArgumentError) GetArgument() any {
return e.argument
}

func NewIllegalArgumentError(argument any) *IllegalArgumentError {
return &IllegalArgumentError{
argument: argument,
}
}
90 changes: 90 additions & 0 deletions tools/diagnostics/default-diagnostic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

import (
"ballerina-lang-go/tools/text"
"fmt"
)

// DefaultDiagnostic is an internal implementation of the Diagnostic interface that is used by the DiagnosticFactory
// to create diagnostics.
type DefaultDiagnostic interface {
Diagnostic
}

type defaultDiagnosticImpl struct {
diagnosticBase
diagnosticInfo DiagnosticInfo
location Location
properties []DiagnosticProperty[any]
message string
}

func NewDefaultDiagnostic(diagnosticInfo DiagnosticInfo, location Location, properties []DiagnosticProperty[any], args ...any) DefaultDiagnostic {
message := formatMessage(diagnosticInfo.MessageFormat(), args...)
return &defaultDiagnosticImpl{
diagnosticBase: diagnosticBase{},
diagnosticInfo: diagnosticInfo,
location: location,
properties: properties,
message: message,
}
}

func (dd *defaultDiagnosticImpl) Location() Location {
return dd.location
}

func (dd *defaultDiagnosticImpl) DiagnosticInfo() DiagnosticInfo {
return dd.diagnosticInfo
}

func (dd *defaultDiagnosticImpl) Message() string {
return dd.message
}

func (dd *defaultDiagnosticImpl) Properties() []DiagnosticProperty[any] {
return dd.properties
}

func (dd *defaultDiagnosticImpl) String() string {
lineRange := dd.location.LineRange()
filePath := lineRange.FileName()

startLine := lineRange.StartLine()
endLine := lineRange.EndLine()

oneBasedStartLine := text.LinePositionFromLineAndOffset(startLine.Line()+1, startLine.Offset()+1)
oneBasedEndLine := text.LinePositionFromLineAndOffset(endLine.Line()+1, endLine.Offset()+1)
oneBasedLineRange := text.LineRangeFromLinePositions(filePath, oneBasedStartLine, oneBasedEndLine)

return fmt.Sprintf("%s [%s:%s] %s",
dd.diagnosticInfo.Severity().String(),
filePath,
oneBasedLineRange.String(),
dd.Message())
}

func formatMessage(format string, args ...any) string {
if len(args) == 0 {
return format
}
return fmt.Sprintf(format, args...)
}
27 changes: 27 additions & 0 deletions tools/diagnostics/diagnostic-code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// DiagnosticCode represents a diagnostic code.
// Diagnostic code uniquely identifies a diagnostic.
type DiagnosticCode interface {
Severity() DiagnosticSeverity
DiagnosticId() string
MessageKey() string
}
44 changes: 44 additions & 0 deletions tools/diagnostics/diagnostic-factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package diagnostics

// CreateDiagnostic creates a Diagnostic instance from the given details.
//
// Parameters:
// - diagnosticInfo: static diagnostic information
// - location: the location of the diagnostic
// - args: arguments to diagnostic message format
//
// Returns a Diagnostic instance.
func CreateDiagnostic(diagnosticInfo DiagnosticInfo, location Location, args ...any) Diagnostic {
return NewDefaultDiagnostic(diagnosticInfo, location, []DiagnosticProperty[any]{}, args...)
}

// CreateDiagnosticWithProperties creates a Diagnostic instance from the given details.
//
// Parameters:
// - diagnosticInfo: static diagnostic information
// - location: the location of the diagnostic
// - properties: properties associated with the diagnostic
// - args: arguments to diagnostic message format
//
// Returns a Diagnostic instance.
func CreateDiagnosticWithProperties(diagnosticInfo DiagnosticInfo, location Location, properties []DiagnosticProperty[any], args ...any) Diagnostic {
return NewDefaultDiagnostic(diagnosticInfo, location, properties, args...)
}
Loading
Loading