clean up
This commit is contained in:
39
AGENTS.md
39
AGENTS.md
@@ -26,39 +26,37 @@ reichard.io/poiesis/
|
|||||||
│ ├── runtime/ # Runtime management, transpilation, execution
|
│ ├── runtime/ # Runtime management, transpilation, execution
|
||||||
│ │ ├── runtime.go
|
│ │ ├── runtime.go
|
||||||
│ │ └── runtime_test.go
|
│ │ └── runtime_test.go
|
||||||
│ ├── builtin/ # Builtin registration framework
|
│ ├── functions/ # Function registration framework
|
||||||
│ │ ├── types.go
|
│ │ ├── collector.go
|
||||||
│ │ ├── registry.go
|
│ │ ├── registry.go
|
||||||
│ │ ├── wrapper.go
|
│ │ ├── types.go
|
||||||
│ │ ├── convert.go
|
|
||||||
│ │ ├── typescript.go
|
│ │ ├── typescript.go
|
||||||
│ │ └── builtin_test.go
|
│ │ ├── typescript_test.go
|
||||||
│ └── standard/ # Standard builtin implementations
|
│ │ └── functions_test.go
|
||||||
|
│ └── stdlib/ # Standard library implementations
|
||||||
│ ├── fetch.go
|
│ ├── fetch.go
|
||||||
│ ├── fetch_test.go
|
│ └── fetch_test.go
|
||||||
│ └── fetch_promise_test.go
|
|
||||||
└── test_data/ # Test TypeScript files
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Packages
|
## Key Packages
|
||||||
|
|
||||||
- `reichard.io/poiesis/internal/runtime` - Runtime management, TypeScript transpilation, JavaScript execution
|
- `reichard.io/poiesis/internal/runtime` - Runtime management, TypeScript transpilation, JavaScript execution
|
||||||
- `reichard.io/poiesis/internal/builtin` - Generic builtin registration framework (sync/async wrappers, automatic JS/Go conversion via JSON, type definition generation)
|
- `reichard.io/poiesis/internal/functions` - Generic function registration framework (sync/async wrappers, automatic JS/Go conversion via JSON, type definition generation)
|
||||||
- `reichard.io/poiesis/internal/standard` - Standard builtin implementations (fetch, add, greet, etc.)
|
- `reichard.io/poiesis/internal/stdlib` - Standard library implementations (fetch)
|
||||||
|
|
||||||
## Builtin System
|
## Function System
|
||||||
|
|
||||||
### Registration
|
### Registration
|
||||||
|
|
||||||
Two types of builtins:
|
Two types of functions:
|
||||||
- **Sync**: `RegisterBuiltin[T, R](name, fn)` - executes synchronously, returns value
|
- **Sync**: `RegisterFunction[T, R](name, fn)` - executes synchronously, returns value
|
||||||
- **Async**: `RegisterAsyncBuiltin[T, R](name, fn)` - runs in goroutine, returns Promise
|
- **Async**: `RegisterAsyncFunction[T, R](name, fn)` - runs in goroutine, returns Promise
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
- Args must be a struct implementing `Args` interface with `Validate() error` method
|
- Args must be a struct implementing `Args` interface with `Validate() error` method
|
||||||
- Use JSON tags for TypeScript type definitions
|
- Use JSON tags for TypeScript type definitions
|
||||||
- Async builtins automatically generate `Promise<R>` return types
|
- Async functions automatically generate `Promise<R>` return types
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
@@ -74,11 +72,11 @@ func Add(_ context.Context, args AddArgs) (int, error) {
|
|||||||
return args.A + args.B, nil
|
return args.A + args.B, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register sync builtin
|
// Register sync function
|
||||||
builtin.RegisterBuiltin[AddArgs, int]("add", Add)
|
functions.RegisterFunction[AddArgs, int]("add", Add)
|
||||||
|
|
||||||
// Register async builtin
|
// Register async function
|
||||||
builtin.RegisterAsyncBuiltin[FetchArgs, *FetchResult]("fetch", Fetch)
|
functions.RegisterAsyncFunction[FetchArgs, *FetchResult]("fetch", Fetch)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing Patterns
|
## Testing Patterns
|
||||||
@@ -87,6 +85,7 @@ builtin.RegisterAsyncBuiltin[FetchArgs, *FetchResult]("fetch", Fetch)
|
|||||||
- **Assertions**: `github.com/stretchr/testify/assert` and `require`
|
- **Assertions**: `github.com/stretchr/testify/assert` and `require`
|
||||||
- **Linting**: `golangci-lint run` - must pass before committing
|
- **Linting**: `golangci-lint run` - must pass before committing
|
||||||
- **Test organization**: Test files use `_test.go` suffix, test functions prefixed with `Test`
|
- **Test organization**: Test files use `_test.go` suffix, test functions prefixed with `Test`
|
||||||
|
- **TypeScript test files**: Tests that require TypeScript files should create them inline using `os.CreateTemp()` instead of relying on external test files
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
package functions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestArgs struct {
|
|
||||||
Field1 string `json:"field1"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t TestArgs) Validate() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAsyncFunction(t *testing.T) {
|
|
||||||
RegisterAsyncFunction("testAsync", func(_ context.Context, args TestArgs) (string, error) {
|
|
||||||
return "result: " + args.Field1, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
fn, ok := functionRegistry["testAsync"]
|
|
||||||
|
|
||||||
require.True(t, ok, "testAsync should be registered")
|
|
||||||
assert.Contains(t, fn.Definition(), "Promise<string>", "definition should include Promise<string>")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOOD: Test Normal Function
|
|
||||||
@@ -41,17 +41,16 @@ func New(ctx context.Context, opts ...RuntimeOption) (*Runtime, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runtime) populateGlobals() error {
|
func (r *Runtime) populateGlobals() error {
|
||||||
// Register Custom Functions
|
|
||||||
for name, fn := range functions.GetRegisteredFunctions() {
|
for name, fn := range functions.GetRegisteredFunctions() {
|
||||||
// Register Main Function
|
// Register Main Function
|
||||||
if fn.IsAsync() {
|
if fn.IsAsync() {
|
||||||
r.ctx.SetAsyncFunc(name, func(this *qjs.This) {
|
r.ctx.SetAsyncFunc(name, func(this *qjs.This) {
|
||||||
qjsVal, err := callFunc(this, fn)
|
qjsVal, err := callFunc(this, fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Promise().Reject(this.Context().NewError(err))
|
_ = this.Promise().Reject(this.Context().NewError(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Promise().Resolve(qjsVal)
|
_ = this.Promise().Resolve(qjsVal)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
r.ctx.SetFunc(name, func(this *qjs.This) (*qjs.Value, error) {
|
r.ctx.SetFunc(name, func(this *qjs.This) (*qjs.Value, error) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package runtime
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -26,7 +27,44 @@ func TestExecuteTypeScript(t *testing.T) {
|
|||||||
rt, err := New(context.Background(), WithStderr(&stderr), WithStdout(&stdout))
|
rt, err := New(context.Background(), WithStderr(&stderr), WithStdout(&stdout))
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.NoError(t, err, "Expected no error")
|
||||||
|
|
||||||
err = rt.RunFile("../../test_data/test.ts")
|
tsCode := `interface Person {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function greet(person: Person): string {
|
||||||
|
return "Hello, " + person.name + "! You are " + person.age + " years old.";
|
||||||
|
}
|
||||||
|
|
||||||
|
const user: Person = {
|
||||||
|
name: "Alice",
|
||||||
|
age: 30,
|
||||||
|
email: "alice@example.com",
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(greet(user));
|
||||||
|
console.log("Email: " + user.email);
|
||||||
|
|
||||||
|
function calculateSum(a: number, b: number): number {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Sum of 5 and 10 is: " + calculateSum(5, 10));
|
||||||
|
`
|
||||||
|
|
||||||
|
tmpFile, err := os.CreateTemp("", "*.ts")
|
||||||
|
assert.NoError(t, err, "Failed to create temp file")
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = os.Remove(tmpFile.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err = tmpFile.WriteString(tsCode)
|
||||||
|
assert.NoError(t, err, "Failed to write to temp file")
|
||||||
|
err = tmpFile.Close()
|
||||||
|
assert.NoError(t, err, "Failed to close temp file")
|
||||||
|
|
||||||
|
err = rt.RunFile(tmpFile.Name())
|
||||||
|
|
||||||
assert.NoError(t, err, "Expected no error")
|
assert.NoError(t, err, "Expected no error")
|
||||||
assert.Empty(t, stderr.String(), "Expected no error output")
|
assert.Empty(t, stderr.String(), "Expected no error output")
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
try {
|
|
||||||
console.log(1);
|
|
||||||
const response = fetch("https://httpbin.org/get");
|
|
||||||
console.log(2);
|
|
||||||
console.log(response);
|
|
||||||
|
|
||||||
console.log("OK:", response.ok);
|
|
||||||
console.log("Status:", response.status);
|
|
||||||
console.log("Body:", response.body);
|
|
||||||
console.log("Content-Type:", response.headers["content-type"]);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e.message);
|
|
||||||
console.log("exception");
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
async function main() {
|
|
||||||
try {
|
|
||||||
const response = await fetch("https://httpbin.org/get");
|
|
||||||
console.log(response);
|
|
||||||
|
|
||||||
console.log("OK:", response.ok);
|
|
||||||
console.log("Status:", response.status);
|
|
||||||
console.log("Body:", response.body);
|
|
||||||
console.log("Content-Type:", response.headers["content-type"]);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("error");
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
const response = fetch("https://httpbin.org/get");
|
|
||||||
|
|
||||||
console.log("OK:", response.ok);
|
|
||||||
console.log("Status:", response.status);
|
|
||||||
console.log("Body:", response.text());
|
|
||||||
console.log("Content-Type:", response.headers.get("content-type"));
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
async function logPromiseResult() {
|
|
||||||
try {
|
|
||||||
const response = await fetch({input: "https://httpbin.org/get"});
|
|
||||||
console.log("Fetch successful, OK:", response.ok);
|
|
||||||
console.log("Status:", response.status);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Fetch failed:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logPromiseResult();
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
const sum = add(5, 10);
|
|
||||||
console.log("5 + 10 =", sum);
|
|
||||||
|
|
||||||
const greeting = greet("World");
|
|
||||||
console.log(greeting);
|
|
||||||
|
|
||||||
const response = fetch("https://httpbin.org/get");
|
|
||||||
console.log("Fetch OK:", response.ok);
|
|
||||||
console.log("Fetch Status:", response.status);
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
interface Person {
|
|
||||||
name: string;
|
|
||||||
age: number;
|
|
||||||
email: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function greet(person: Person): string {
|
|
||||||
return `Hello, ${person.name}! You are ${person.age} years old.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user: Person = {
|
|
||||||
name: "Alice",
|
|
||||||
age: 30,
|
|
||||||
email: "alice@example.com",
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(greet(user));
|
|
||||||
console.log(`Email: ${user.email}`);
|
|
||||||
|
|
||||||
function calculateSum(a: number, b: number): number {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Sum of 5 and 10 is: ${calculateSum(5, 10)}`);
|
|
||||||
Reference in New Issue
Block a user