Skip to content

Commit

Permalink
Merge pull request #88 from yantrajs/feature/disposable
Browse files Browse the repository at this point in the history
Feature/disposable
  • Loading branch information
ackava committed Sep 12, 2023
2 parents afc222e + 66a1d5f commit a7bb507
Show file tree
Hide file tree
Showing 28 changed files with 723 additions and 92 deletions.
103 changes: 103 additions & 0 deletions YantraJS.Core.Tests/ClrObjects/DisposableTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using Microsoft.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using YantraJS.Core.Clr;
using YantraJS.Utils;

namespace YantraJS.Core.Tests.ClrObjects
{
[TestClass]
public class DisposableTests
{
class DisposableFile : IDisposable
{
public bool Open = true;

public string Value = "";

[JSExport("add")]
public void Add(string text)
{
this.Value += text + "\r\n";
}

public void Dispose()
{
this.Open = false;
}
}

class AsyncDisposableFile : IAsyncDisposable
{
public bool Open = true;

public string Value = "";

[JSExport("add")]
public void Add(string text)
{
this.Value += text + "\r\n";
}

public async ValueTask DisposeAsync()
{
await Task.Delay(10);
this.Open = false;
}
}

[TestMethod]
public void SyncDispose()
{
var c = new JSTestContext();

c["DisposableFile"] = ClrType.From(typeof(DisposableFile));


var a = c.Eval(@"
function use(d) {
using f = d;
f.add('a');
}
var a = new DisposableFile();
use(a);
return a;
");

a.ConvertTo<DisposableFile>(out var d);
Assert.IsFalse(d.Open);
}

[TestMethod]
public void AsyncDispose()
{
AsyncPump.Run(async () =>
{
var c = new JSTestContext();
c["AsyncDisposableFile"] = ClrType.From(typeof(AsyncDisposableFile));
var a = await c.ExecuteAsync(@"
(async function() {
async function use(d) {
await using f = d;
f.add('a');
}
var a = new AsyncDisposableFile();
await use(a);
return a;
})();
");
a.ConvertTo<AsyncDisposableFile>(out var d);
Assert.IsFalse(d.Open);
});
}
}
}
72 changes: 0 additions & 72 deletions YantraJS.Core.Tests/Generator/ES6FilesTest.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
function sleep(n) {
return new Promise((resolve) => {
setTimeout(resolve, n);
});
}

class File {

lines = [];

constructor() {
this.open = true;
}

add(line) {
this.lines.push(line);
}

async disposeAsync() {
await sleep(1);
this.open = false;
}

[Symbol.asyncDispose]() {
return this.disposeAsync();
}
}

async function runTest(f) {
await using file = f;
f.add("1");
f.add("2");
}

var f1 = new File();
assert.strictEqual(true, f1.open);
await runTest(f1);
assert.strictEqual(false, f1.open);
assert.strictEqual("1,2", f1.lines.toString());


class CorruptFile extends File {
[Symbol.asyncDispose]() {
throw new Error("File corrupt");
}
}

var f2 = new CorruptFile();
assert.strictEqual(true, f2.open);
try {
await runTest(f2);
} catch (error) {
console.log(error);
console.log(Object.getPrototypeOf(error).constructor.name);
assert.strictEqual(true, error instanceof SuppressedError);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class File {

lines = [];

constructor() {
this.open = true;
}

add(line) {
this.lines.push(line);
}

[Symbol.dispose]() {
this.open = false;
}
}

function runTest(f) {
using file = f;
f.add("1");
f.add("2");
}

var f1 = new File();
assert.strictEqual(true, f1.open);
runTest(f1);
assert.strictEqual(false, f1.open);
assert.strictEqual("1,2", f1.lines.toString());


class CorruptFile extends File {
[Symbol.dispose]() {
throw new Error("File corrupt");
}
}

var f2 = new CorruptFile();
assert.strictEqual(true, f2.open);
try {
runTest(f2);
} catch (error) {
console.log(error);
console.log(Object.getPrototypeOf(error).constructor.name);
assert.strictEqual(true, error instanceof SuppressedError);
}
11 changes: 11 additions & 0 deletions YantraJS.Core.Tests/Generator/FilesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ public void Syntax()

}

[TestClass]
public class ES2023
{
[TestFolder("es\\2023")]
public void Disposables()
{

}

}

[TestClass]
public class Modules
{
Expand Down
4 changes: 4 additions & 0 deletions YantraJS.Core.Tests/YantraJS.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@
<ProjectReference Include="..\YantraJS.Core\YantraJS.Core.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Generator\Files\es\2023\disposables\" />
</ItemGroup>

</Project>
30 changes: 30 additions & 0 deletions YantraJS.Core/Core/Clr/ClrType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,36 @@ internal void Generate(JSObject target, Type type, bool isStatic)
clrPrototype.GetElementAt = indexGetter;
if (indexSetter != null)
clrPrototype.SetElementAt = indexSetter;

// setup disposables...
var disposableType = typeof(IDisposable);
var asyncDisposableType = typeof(IAsyncDisposable);
if (disposableType.IsAssignableFrom(type) && type.GetInterfaceMap(disposableType)
.InterfaceMethods
.Any())
{
target.FastAddValue(JSSymbol.dispose, new JSFunction((in Arguments a) =>
{
if (a.This is ClrProxy p && p.value is IDisposable d)
{
d.Dispose();
}
return JSUndefined.Value;
}), JSPropertyAttributes.ConfigurableValue);
}
if (asyncDisposableType.IsAssignableFrom(type) && type.GetInterfaceMap(typeof(IAsyncDisposable))
.InterfaceMethods
.Any())
{
target.FastAddValue(JSSymbol.asyncDispose, new JSFunction((in Arguments a) =>
{
if (a.This is ClrProxy p && p.value is IAsyncDisposable d)
{
return ClrProxy.From(d.DisposeAsync().AsTask());
}
return JSUndefined.Value;
}), JSPropertyAttributes.ConfigurableValue);
}
}

private ClrType(
Expand Down
Loading

0 comments on commit a7bb507

Please sign in to comment.