From e87f50956a540b676282d7b8ec5bc8b22cbaea96 Mon Sep 17 00:00:00 2001 From: ekibun Date: Mon, 22 Feb 2021 16:15:46 +0800 Subject: [PATCH] nullsafety --- CHANGELOG.md | 9 +++ example/pubspec.lock | 2 +- lib/src/engine.dart | 57 ++++++++++--------- lib/src/ffi.dart | 72 +++++++++++++----------- lib/src/isolate.dart | 33 ++++++----- lib/src/object.dart | 112 ++++++++++++++++++++----------------- lib/src/wrapper.dart | 19 +++---- pubspec.yaml | 6 +- test/flutter_qjs_test.dart | 6 +- 9 files changed, 176 insertions(+), 140 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6897691..d80fe23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ * @LastEditTime: 2020-12-02 11:36:40 --> +## 0.3.6 + +* upgrade ffi to 1.0.0. +* nullsafety. + +## 0.3.5 + +* downgrade ffi to 0.1.3. + ## 0.3.4 * upgrade ffi to 1.0.0. diff --git a/example/pubspec.lock b/example/pubspec.lock index eba0f46..ac7d3d5 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -75,7 +75,7 @@ packages: path: ".." relative: true source: path - version: "0.3.4" + version: "0.3.6" flutter_test: dependency: "direct dev" description: flutter diff --git a/lib/src/engine.dart b/lib/src/engine.dart index b759958..16c5ed6 100644 --- a/lib/src/engine.dart +++ b/lib/src/engine.dart @@ -15,20 +15,20 @@ typedef _JsHostPromiseRejectionHandler = void Function(dynamic reason); /// Quickjs engine for flutter. class FlutterQjs { - Pointer _rt; - Pointer _ctx; + Pointer? _rt; + Pointer? _ctx; /// Max stack size for quickjs. - final int stackSize; + final int? stackSize; /// Message Port for event loop. Close it to stop dispatching event loop. ReceivePort port = ReceivePort(); /// Handler function to manage js module. - _JsModuleHandler moduleHandler; + final _JsModuleHandler? moduleHandler; /// Handler function to manage js module. - _JsHostPromiseRejectionHandler hostPromiseRejectionHandler; + final _JsHostPromiseRejectionHandler? hostPromiseRejectionHandler; FlutterQjs({ this.moduleHandler, @@ -38,7 +38,7 @@ class FlutterQjs { _ensureEngine() { if (_rt != null) return; - _rt = jsNewRuntime((ctx, type, ptr) { + final rt = jsNewRuntime((ctx, type, ptr) { try { switch (type) { case JSChannelType.METHON: @@ -65,7 +65,7 @@ class FlutterQjs { )); case JSChannelType.MODULE: if (moduleHandler == null) throw JSError('No ModuleHandler'); - final ret = moduleHandler( + final ret = moduleHandler!( ptr.cast().toDartString(), ).toNativeUtf8(); Future.microtask(() { @@ -75,15 +75,14 @@ class FlutterQjs { case JSChannelType.PROMISE_TRACK: final err = _parseJSException(ctx, ptr); if (hostPromiseRejectionHandler != null) { - hostPromiseRejectionHandler(err); + hostPromiseRejectionHandler!(err); } else { print('unhandled promise rejection: $err'); } return nullptr; case JSChannelType.FREE_OBJECT: final rt = ctx.cast(); - _DartObject obj = _DartObject.fromAddress(rt, ptr.address); - obj?.free(); + _DartObject.fromAddress(rt, ptr.address)?.free(); return nullptr; } throw JSError('call channel with wrong type'); @@ -106,20 +105,21 @@ class FlutterQjs { return err; } }, port); - if (this.stackSize != null && this.stackSize > 0) - jsSetMaxStackSize(_rt, this.stackSize); - _ctx = jsNewContext(_rt); + final stackSize = this.stackSize ?? 0; + if (stackSize > 0) jsSetMaxStackSize(rt, stackSize); + _rt = rt; + _ctx = jsNewContext(rt); } /// Free Runtime and Context which can be recreate when evaluate again. close() { - if (_rt == null) return; final rt = _rt; final ctx = _ctx; - _executePendingJob(); _rt = null; _ctx = null; - jsFreeContext(ctx); + if (ctx != null) jsFreeContext(ctx); + if (rt == null) return; + _executePendingJob(); try { jsFreeRuntime(rt); } on String catch (e) { @@ -128,11 +128,13 @@ class FlutterQjs { } void _executePendingJob() { - if (_rt == null) return; + final rt = _rt; + final ctx = _ctx; + if (rt == null || ctx == null) return; while (true) { - int err = jsExecutePendingJob(_rt); + int err = jsExecutePendingJob(rt); if (err <= 0) { - if (err < 0) print(_parseJSException(_ctx)); + if (err < 0) print(_parseJSException(ctx)); break; } } @@ -146,20 +148,25 @@ class FlutterQjs { } /// Evaluate js script. - dynamic evaluate(String command, {String name, int evalFlags}) { + dynamic evaluate( + String command, { + String? name, + int? evalFlags, + }) { _ensureEngine(); + final ctx = _ctx!; final jsval = jsEval( - _ctx, + ctx, command, name ?? '', evalFlags ?? JSEvalFlag.GLOBAL, ); if (jsIsException(jsval) != 0) { - jsFreeValue(_ctx, jsval); - throw _parseJSException(_ctx); + jsFreeValue(ctx, jsval); + throw _parseJSException(ctx); } - final result = _jsToDart(_ctx, jsval); - jsFreeValue(_ctx, jsval); + final result = _jsToDart(ctx, jsval); + jsFreeValue(ctx, jsval); return result; } } diff --git a/lib/src/ffi.dart b/lib/src/ffi.dart index 36f6c9c..3522149 100644 --- a/lib/src/ffi.dart +++ b/lib/src/ffi.dart @@ -10,6 +10,16 @@ import 'dart:io'; import 'dart:isolate'; import 'package:ffi/ffi.dart'; +extension ListFirstWhere on Iterable { + T? firstWhereOrNull(bool Function(T) test) { + try { + return firstWhere(test); + } on StateError { + return null; + } + } +} + abstract class JSRef { int _refCount = 0; void dup() { @@ -34,7 +44,7 @@ abstract class JSRef { static void _callRecursive( dynamic obj, void Function(JSRef) cb, [ - Set cache, + Set? cache, ]) { if (obj == null) return; if (cache == null) cache = Set(); @@ -155,24 +165,26 @@ final Pointer Function( .asFunction(); class _RuntimeOpaque { - _JSChannel _channel; + final _JSChannel _channel; List _ref = []; - ReceivePort _port; - int _dartObjectClassId; - get dartObjectClassId => _dartObjectClassId; + final ReceivePort _port; + int? _dartObjectClassId; + _RuntimeOpaque(this._channel, this._port); + + int? get dartObjectClassId => _dartObjectClassId; void addRef(JSRef ref) => _ref.add(ref); bool removeRef(JSRef ref) => _ref.remove(ref); - JSRef getRef(bool Function(JSRef ref) test) { - return _ref.firstWhere(test, orElse: () => null); + JSRef? getRef(bool Function(JSRef ref) test) { + return _ref.firstWhereOrNull(test); } } final Map, _RuntimeOpaque> runtimeOpaques = Map(); -Pointer channelDispacher( +Pointer? channelDispacher( Pointer ctx, int type, Pointer argv, @@ -188,9 +200,7 @@ Pointer jsNewRuntime( ReceivePort port, ) { final rt = _jsNewRuntime(Pointer.fromFunction(channelDispacher)); - runtimeOpaques[rt] = _RuntimeOpaque() - .._channel = callback - .._port = port; + runtimeOpaques[rt] = _RuntimeOpaque(callback, port); return rt; } @@ -222,21 +232,22 @@ void jsFreeRuntime( Pointer rt, ) { final referenceleak = []; - while (true) { - final ref = runtimeOpaques[rt] - ?._ref - ?.firstWhere((ref) => ref is JSRefLeakable, orElse: () => null); - if (ref == null) break; - ref.destroy(); - runtimeOpaques[rt]?._ref?.remove(ref); - } - while (0 < runtimeOpaques[rt]?._ref?.length ?? 0) { - final ref = runtimeOpaques[rt]?._ref?.first; - final objStrs = ref.toString().split('\n'); - final objStr = objStrs.length > 0 ? objStrs[0] + " ..." : objStrs[0]; - referenceleak.add( - " ${identityHashCode(ref)}\t${ref._refCount + 1}\t${ref.runtimeType.toString()}\t$objStr"); - ref.destroy(); + final opaque = runtimeOpaques[rt]; + if (opaque != null) { + while (true) { + final ref = opaque._ref.firstWhereOrNull((ref) => ref is JSRefLeakable); + if (ref == null) break; + ref.destroy(); + runtimeOpaques[rt]?._ref.remove(ref); + } + while (opaque._ref.isNotEmpty) { + final ref = opaque._ref.first; + final objStrs = ref.toString().split('\n'); + final objStr = objStrs.length > 0 ? objStrs[0] + " ..." : objStrs[0]; + referenceleak.add( + " ${identityHashCode(ref)}\t${ref._refCount + 1}\t${ref.runtimeType.toString()}\t$objStr"); + ref.destroy(); + } } _jsFreeRuntime(rt); if (referenceleak.length > 0) { @@ -335,7 +346,7 @@ Pointer jsEval( ); malloc.free(utf8input); malloc.free(utf8filename); - runtimeOpaques[jsGetRuntime(ctx)]._port.sendPort.send(#eval); + runtimeOpaques[jsGetRuntime(ctx)]?._port.sendPort.send(#eval); return val; } @@ -915,14 +926,11 @@ Pointer jsCall( setJSValueList(jsArgs, i, jsArg); } final func1 = jsDupValue(ctx, funcObj); - final _thisObj = thisObj ?? jsUNDEFINED(); + final _thisObj = thisObj; final jsRet = _jsCall(ctx, funcObj, _thisObj, argv.length, jsArgs); - if (thisObj == null) { - jsFreeValue(ctx, _thisObj); - } jsFreeValue(ctx, func1); malloc.free(jsArgs); - runtimeOpaques[jsGetRuntime(ctx)]._port.sendPort.send(#call); + runtimeOpaques[jsGetRuntime(ctx)]?._port.sendPort.send(#call); return jsRet; } diff --git a/lib/src/isolate.dart b/lib/src/isolate.dart index 2a81a7f..60b91be 100644 --- a/lib/src/isolate.dart +++ b/lib/src/isolate.dart @@ -17,7 +17,7 @@ abstract class _IsolateEncodable { Map _encode(); } -dynamic _encodeData(dynamic data, {Map cache}) { +dynamic _encodeData(dynamic data, {Map? cache}) { if (cache == null) cache = Map(); if (cache.containsKey(data)) return cache[data]; if (data is _IsolateEncodable) return data._encode(); @@ -58,7 +58,7 @@ dynamic _encodeData(dynamic data, {Map cache}) { return data; } -dynamic _decodeData(dynamic data, {Map cache}) { +dynamic _decodeData(dynamic data, {Map? cache}) { if (cache == null) cache = Map(); if (cache.containsKey(data)) return cache[data]; if (data is List) { @@ -132,7 +132,7 @@ void _runJsIsolate(Map spawnMessage) async { ); port.listen((msg) async { var data; - SendPort msgPort = msg[#port]; + SendPort? msgPort = msg[#port]; try { switch (msg[#type]) { case #evaluate: @@ -164,16 +164,16 @@ void _runJsIsolate(Map spawnMessage) async { typedef _JsAsyncModuleHandler = Future Function(String name); class IsolateQjs { - Future _sendPort; + Future? _sendPort; /// Max stack size for quickjs. - final int stackSize; + final int? stackSize; /// Asynchronously handler to manage js module. - _JsAsyncModuleHandler moduleHandler; + final _JsAsyncModuleHandler? moduleHandler; /// Handler function to manage js module. - _JsHostPromiseRejectionHandler hostPromiseRejectionHandler; + final _JsHostPromiseRejectionHandler? hostPromiseRejectionHandler; /// Quickjs engine runing on isolate thread. /// @@ -207,7 +207,7 @@ class IsolateQjs { try { final err = _decodeData(msg[#reason]); if (hostPromiseRejectionHandler != null) { - hostPromiseRejectionHandler(err); + hostPromiseRejectionHandler!(err); } else { print('unhandled promise rejection: $err'); } @@ -218,7 +218,7 @@ class IsolateQjs { case #module: final ptr = Pointer.fromAddress(msg[#ptr]); try { - ptr.value = (await moduleHandler(msg[#name])).toNativeUtf8(); + ptr.value = (await moduleHandler!(msg[#name])).toNativeUtf8(); } catch (e) { ptr.value = Pointer.fromAddress(-1); } @@ -234,8 +234,10 @@ class IsolateQjs { /// Free Runtime and close isolate thread that can be recreate when evaluate again. close() { - if (_sendPort == null) return; - final ret = _sendPort.then((sendPort) async { + final sendPort = _sendPort; + _sendPort = null; + if (sendPort == null) return; + final ret = sendPort.then((sendPort) async { final closePort = ReceivePort(); sendPort.send({ #type: #close, @@ -247,15 +249,18 @@ class IsolateQjs { throw _decodeData(result[#error]); return _decodeData(result); }); - _sendPort = null; return ret; } /// Evaluate js script. - Future evaluate(String command, {String name, int evalFlags}) async { + Future evaluate( + String command, { + String? name, + int? evalFlags, + }) async { _ensureEngine(); final evaluatePort = ReceivePort(); - final sendPort = await _sendPort; + final sendPort = await _sendPort!; sendPort.send({ #type: #evaluate, #command: command, diff --git a/lib/src/object.dart b/lib/src/object.dart index 0240f5d..eb0f79c 100644 --- a/lib/src/object.dart +++ b/lib/src/object.dart @@ -48,17 +48,18 @@ class _DartFunction extends JSInvokable { /// implement this to capture js object release. class _DartObject extends JSRef implements JSRefLeakable { - Object _obj; - Pointer _ctx; - _DartObject(this._ctx, this._obj) { - if (_obj is JSRef) { - (_obj as JSRef).dup(); - } - runtimeOpaques[jsGetRuntime(_ctx)]?.addRef(this); + Object? _obj; + Pointer? _ctx; + _DartObject(Pointer ctx, dynamic obj) { + _ctx = ctx; + _obj = obj; + if (obj is JSRef) obj.dup(); + runtimeOpaques[jsGetRuntime(ctx)]?.addRef(this); } - static _DartObject fromAddress(Pointer rt, int val) { - return runtimeOpaques[rt]?.getRef((e) => identityHashCode(e) == val); + static _DartObject? fromAddress(Pointer rt, int val) { + return runtimeOpaques[rt]?.getRef((e) => identityHashCode(e) == val) + as _DartObject?; } @override @@ -69,20 +70,20 @@ class _DartObject extends JSRef implements JSRefLeakable { @override void destroy() { - if (_ctx == null) return; - runtimeOpaques[jsGetRuntime(_ctx)]?.removeRef(this); + final ctx = _ctx; + final obj = _obj; _ctx = null; - if (_obj is JSRef) { - (_obj as JSRef).free(); - } _obj = null; + if (ctx == null) return; + runtimeOpaques[jsGetRuntime(ctx)]?.removeRef(this); + if (obj is JSRef) obj.free(); } } /// JS Error wrapper class JSError extends _IsolateEncodable { - String message; - String stack; + late String message; + late String stack; JSError(message, [stack]) { if (message is JSError) { this.message = message.message; @@ -95,10 +96,10 @@ class JSError extends _IsolateEncodable { @override String toString() { - return stack == null ? message.toString() : "$message\n$stack"; + return stack.isEmpty ? message.toString() : "$message\n$stack"; } - static JSError _decode(Map obj) { + static JSError? _decode(Map obj) { if (obj.containsKey(#jsError)) return JSError(obj[#jsError], obj[#jsErrorStack]); return null; @@ -116,30 +117,33 @@ class JSError extends _IsolateEncodable { /// JS Object reference /// call [release] to release js object. class _JSObject extends JSRef { - Pointer _val; - Pointer _ctx; + Pointer? _val; + Pointer? _ctx; /// Create - _JSObject(this._ctx, Pointer _val) { - final rt = jsGetRuntime(_ctx); - this._val = jsDupValue(_ctx, _val); + _JSObject(Pointer ctx, Pointer val) { + this._ctx = ctx; + final rt = jsGetRuntime(ctx); + this._val = jsDupValue(ctx, val); runtimeOpaques[rt]?.addRef(this); } @override void destroy() { - if (_val == null) return; - final rt = jsGetRuntime(_ctx); - runtimeOpaques[rt]?.removeRef(this); - jsFreeValue(_ctx, _val); + final ctx = _ctx; + final val = _val; _val = null; _ctx = null; + if (ctx == null || val == null) return; + final rt = jsGetRuntime(ctx); + runtimeOpaques[rt]?.removeRef(this); + jsFreeValue(ctx, val); } @override String toString() { - if (_val == null) return "JSObject(released)"; - return jsToCString(_ctx, _val); + if (_ctx == null || _val == null) return "JSObject(released)"; + return jsToCString(_ctx!, _val!); } } @@ -150,29 +154,32 @@ class _JSFunction extends _JSObject implements JSInvokable, _IsolateEncodable { @override invoke(List arguments, [dynamic thisVal]) { final jsRet = _invoke(arguments, thisVal); - if (jsRet == null) return; + final ctx = _ctx!; bool isException = jsIsException(jsRet) != 0; if (isException) { - jsFreeValue(_ctx, jsRet); - throw _parseJSException(_ctx); + jsFreeValue(ctx, jsRet); + throw _parseJSException(ctx); } - final ret = _jsToDart(_ctx, jsRet); - jsFreeValue(_ctx, jsRet); + final ret = _jsToDart(ctx, jsRet); + jsFreeValue(ctx, jsRet); return ret; } Pointer _invoke(List arguments, [dynamic thisVal]) { - if (_val == null) throw JSError("InternalError: JSValue released"); + final ctx = _ctx; + final val = _val; + if (ctx == null || val == null) + throw JSError("InternalError: JSValue released"); final args = arguments .map( - (e) => _dartToJs(_ctx, e), + (e) => _dartToJs(ctx, e), ) .toList(); - final jsThis = _dartToJs(_ctx, thisVal); - final jsRet = jsCall(_ctx, _val, jsThis, args); - jsFreeValue(_ctx, jsThis); + final jsThis = _dartToJs(ctx, thisVal); + final jsRet = jsCall(ctx, val, jsThis, args); + jsFreeValue(ctx, jsThis); for (final jsArg in args) { - jsFreeValue(_ctx, jsArg); + jsFreeValue(ctx, jsArg); } return jsRet; } @@ -185,9 +192,9 @@ class _JSFunction extends _JSObject implements JSInvokable, _IsolateEncodable { /// Dart function wrapper for isolate class IsolateFunction extends JSInvokable implements _IsolateEncodable { - int _isolateId; - SendPort _port; - JSInvokable _invokable; + int? _isolateId; + SendPort? _port; + JSInvokable? _invokable; IsolateFunction._fromId(this._isolateId, this._port); IsolateFunction._new(this._invokable) { @@ -195,18 +202,17 @@ class IsolateFunction extends JSInvokable implements _IsolateEncodable { } IsolateFunction(Function func) : this._new(_DartFunction(func)); - static ReceivePort _invokeHandler; + static ReceivePort? _invokeHandler; static Set _handlers = Set(); static get _handlePort { if (_invokeHandler == null) { _invokeHandler = ReceivePort(); - _invokeHandler.listen((msg) async { + _invokeHandler!.listen((msg) async { final msgPort = msg[#port]; try { - final handler = _handlers.firstWhere( + final handler = _handlers.firstWhereOrNull( (v) => identityHashCode(v) == msg[#handler], - orElse: () => null, ); if (handler == null) throw JSError('handler released'); final ret = _encodeData(await handler._handle(msg[#msg])); @@ -220,13 +226,14 @@ class IsolateFunction extends JSInvokable implements _IsolateEncodable { } }); } - return _invokeHandler.sendPort; + return _invokeHandler!.sendPort; } _send(msg) async { - if (_port == null) return _handle(msg); + final port = _port; + if (port == null) return _handle(msg); final evaluatePort = ReceivePort(); - _port.send({ + port.send({ #handler: _isolateId, #msg: msg, #port: evaluatePort.sendPort, @@ -240,6 +247,7 @@ class IsolateFunction extends JSInvokable implements _IsolateEncodable { _destroy() { _handlers.remove(this); _invokable?.free(); + _invokable = null; } _handle(msg) async { @@ -257,7 +265,7 @@ class IsolateFunction extends JSInvokable implements _IsolateEncodable { } final List args = _decodeData(msg[#args]); final thisVal = _decodeData(msg[#thisVal]); - return _invokable.invoke(args, thisVal); + return _invokable?.invoke(args, thisVal); } @override @@ -270,7 +278,7 @@ class IsolateFunction extends JSInvokable implements _IsolateEncodable { }); } - static IsolateFunction _decode(Map obj) { + static IsolateFunction? _decode(Map obj) { if (obj.containsKey(#jsFunctionPort)) return IsolateFunction._fromId( obj[#jsFunctionId], diff --git a/lib/src/wrapper.dart b/lib/src/wrapper.dart index 2ec462a..cb23d1d 100644 --- a/lib/src/wrapper.dart +++ b/lib/src/wrapper.dart @@ -7,7 +7,7 @@ */ part of '../flutter_qjs.dart'; -dynamic _parseJSException(Pointer ctx, [Pointer perr]) { +dynamic _parseJSException(Pointer ctx, [Pointer? perr]) { final e = perr ?? jsGetException(ctx); var err; try { @@ -24,7 +24,7 @@ void _definePropertyValue( Pointer obj, dynamic key, dynamic val, { - Map> cache, + Map>? cache, }) { final jsAtomVal = _dartToJs(ctx, key, cache: cache); final jsAtom = jsValueToAtom(ctx, jsAtomVal); @@ -43,7 +43,7 @@ Pointer _jsGetPropertyValue( Pointer ctx, Pointer obj, dynamic key, { - Map cache, + Map>? cache, }) { final jsAtomVal = _dartToJs(ctx, key, cache: cache); final jsAtom = jsValueToAtom(ctx, jsAtomVal); @@ -54,7 +54,7 @@ Pointer _jsGetPropertyValue( } Pointer _dartToJs(Pointer ctx, dynamic val, - {Map> cache}) { + {Map>? cache}) { if (val == null) return jsUNDEFINED(); if (val is Error) return _dartToJs(ctx, JSError(val, val.stackTrace)); if (val is Exception) return _dartToJs(ctx, JSError(val)); @@ -65,7 +65,7 @@ Pointer _dartToJs(Pointer ctx, dynamic val, _definePropertyValue(ctx, ret, "stack", val.stack); return ret; } - if (val is _JSObject) return jsDupValue(ctx, val._val); + if (val is _JSObject) return jsDupValue(ctx, val._val!); if (val is Future) { final resolvingFunc = malloc(sizeOfJSValue * 2).cast(); final resolvingFunc2 = @@ -104,7 +104,7 @@ Pointer _dartToJs(Pointer ctx, dynamic val, return ret; } if (cache.containsKey(val)) { - return jsDupValue(ctx, cache[val]); + return jsDupValue(ctx, cache[val]!); } if (val is List) { final ret = jsNewArray(ctx); @@ -141,7 +141,7 @@ Pointer _dartToJs(Pointer ctx, dynamic val, } dynamic _jsToDart(Pointer ctx, Pointer val, - {Map cache}) { + {Map? cache}) { if (cache == null) cache = Map(); final tag = jsValueGetTag(val); if (jsTagIsFloat64(tag) != 0) { @@ -156,8 +156,8 @@ dynamic _jsToDart(Pointer ctx, Pointer val, return jsToCString(ctx, val); case JSTag.OBJECT: final rt = jsGetRuntime(ctx); - final dartObjectClassId = runtimeOpaques[rt].dartObjectClassId; - if (dartObjectClassId != 0) { + final dartObjectClassId = runtimeOpaques[rt]?.dartObjectClassId; + if (dartObjectClassId != null) { final dartObject = _DartObject.fromAddress( rt, jsGetObjectOpaque(val, dartObjectClassId)); if (dartObject != null) return dartObject._obj; @@ -243,7 +243,6 @@ dynamic _jsToDart(Pointer ctx, Pointer val, malloc.free(ptab); return ret; } - break; default: } return null; diff --git a/pubspec.yaml b/pubspec.yaml index 77b5ccd..e000925 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: flutter_qjs description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports all the platforms except web! -version: 0.3.4 +version: 0.3.6 homepage: https://github.com/ekibun/flutter_qjs environment: - sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.20.0 <2.0.0" + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: diff --git a/test/flutter_qjs_test.dart b/test/flutter_qjs_test.dart index 18036f0..ea033f5 100644 --- a/test/flutter_qjs_test.dart +++ b/test/flutter_qjs_test.dart @@ -135,7 +135,7 @@ void main() async { }); test('isolate bind this', () async { final qjs = IsolateQjs(); - JSInvokable localVar; + JSInvokable? localVar; JSInvokable setToGlobal = await qjs .evaluate('(name, func)=>{ this[name] = func }', name: ''); final func = IsolateFunction((args) { @@ -146,8 +146,8 @@ void main() async { func.free(); setToGlobal.free(); final testFuncRet = await qjs.evaluate('test(()=>"ret")', name: ''); - expect(await localVar.invoke([]), 'ret', reason: 'bind function'); - localVar.free(); + expect(await localVar?.invoke([]), 'ret', reason: 'bind function'); + localVar?.free(); expect(testFuncRet, 'ret', reason: 'bind function args return'); await qjs.close(); });