Open alfonsogarciacaro opened 2 years ago
Let me take a look then
The Mirror reflection API looks promising.
Wow. F# app on macbook
A very quick summary of my findings so far:
Flutter is based upon dart. Flutter knows what dart is, dart doesn't know what flutter is
Flutter can create a MacOS app, so we can write output bindings direct to file system using reflection. However:
Dart has Mirrors for reflection, but Flutter does not support Mirrors => we can't reflect on MaterialApp, Scaffold etc from a flutter app. An attempt to use Mirrors in Flutter produces a compilation/runtime error (I can't recall), and research on Stackoverflow backs this up
Dart cannot (easily) load the flutter packages (eg 'package:flutter/material.dart', or even '../../flutter/lib/material.dart' eg) => this blocks the approach of using a Dart application to reflect on the flutter packages. Searches on "dart applications that use Flutter" result in "use flutter", understandably.
Flutter has a relection package named "reflectable" which looks promising, but a simple example didn't compile.
What to look at next:
Dartdoc is the tool that generates this kind of documentation and the ones on pub.dev that already describes the public API for each library. Looking at the html it generates it could be feasible to parse them directly, but I still believe that the ideal solution could be reviving this issue so we could use the output to generate our bindings or forking/rewriting to our needs to generate them directly.
It even has an --auto-include-dependencies
flag that generates documentation files for direct and indirect dependencies, so pretty powerful tool.
Nice! I will help on this π€
When importing the dartdoc package, we can create a Dartdoc
instance calling the constructor Dartdoc.withEmptyGenerator
. There is a brittle generator
field on it with a @visibleForTesting
annotation that we could leverage. The Generator
receives a PackageGraph
that describes everything on the package and a FileWriter
to write the result.
I'm doing some experiments with it to learn the layout to extract everything we need, but that way we probably can use the tool as is.
A hand-made parser would make sense. So would be possible to extend ts2fable to support Dart and more languages?
I upload the test file I made in this repository. I started handling only the constructors for now and got this result for the flutter library. Function types, the generics on the arguments and the translation from core types are still not correctly handled, but it's already a start.
While it's cool that it's using the metadata from the language and loading everything needed into the context so we could handle as we want, it makes it terribly slow. I ran it against my elmish-like lib with almost no dependencies and it takes around 2 minutes to reach the generator.
Amazing. The speed issue makes it hard to test/debug, but once completed this thing only needs to be run occasionally (to keep bindings in sync), I would think?
Yes, we could plug some pre-analysis step to check for changes only start the generation if there is a new or different version package. Maybe we could create a project and save a copy of the pubspec.lock and compare them. If there is a change, we regenerate all files again as it is easier than detecting changes on a single package.
For the named constructors I mapped them as static methods that return an instance of the class. Is that the right way to map them?
Thanks everybody for your help! This is great @Nhowka, even if it requires some manual tweaking it's already a great help to make some demos/samples for the alpha release π As @davedawkins says speed probably it's not an issue if we only need to run the tool once in a while. For prototyping, is it faster if we work with a small code sample or most of the boot up time is taken by Dartdoc.
@adelarsq About ts2fable, probably the only part we could reuse would be printing and it has its own AST which may not have all the information we need (const constructors, named params) so it may be faster for now to do things in Dart directly as @Nhowka did π
About compiling named constructors as static members, this is fine as in Dart they're syntactically the same in the call site. You can also use the [<IsConst>]
attribute in a static member if needed: https://github.com/alfonsogarciacaro/fable-flutterapp/blob/1a80389301c32f8a763bdac93f60c864ee07608d/src/Flutter.Material.fs#L65
@Nhowka I'm trying to edit your code a bit to get bindings for the constructors of the Material widgets. See this commit: https://github.com/alfonsogarciacaro/DartToFableBindings/commit/b7728ac5afbf9fd829585cd2765c9f0b14afb1e0
I tried with a test Dart package and it seemed to work fine, however I downloaded the flutter repo, followed the instructions here and managed to run flutter analyze
in packages/flutter dir without issues. However when I try to run the fsgen from that dir I don't get any output. This is the command I'm using:
dart run ../../../DartToFableBindings/bin/fsgen.dart \
--exclude 'dart:async,dart:collection,dart:convert,dart:core,dart:developer,dart:io,dart:isolate,dart:math,dart:typed_data,dart,dart:ffi,dart:html,dart:js,dart:ui,dart:js_util' \
--show-progress \
--no-auto-include-dependencies \
--no-validate-links \
--no-verbose-warnings \
--no-allow-non-local-warnings \
--no-allow-tools
I only get many errors, this is the shortened log (only start and finish):
../../../../AppData/Local/Pub/Cache/hosted/pub.dartlang.org/dartdoc-5.0.1/lib/src/model/model_element.dart:706:14: Warning: Operand of null-aware operation '?.' has type 'LineInfo' which excludes null.
- 'LineInfo' is from 'package:analyzer/source/line_info.dart' ('../../../../AppData/Local/Pub/Cache/hosted/pub.dartlang.org/analyzer-3.4.1/lib/source/line_info.dart').
return lineInfo?.getLocation(nameOffset);
^
Documenting flutter...
error: private API of package:Dart is reexported by libraries in other packages:
from cupertino.Color: (file:///C:/Users/alfon/repos/flutter/bin/cache/pkg/sky_engine/lib/ui/painting.dart:94:7)
referred to by cupertino: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/cupertino.dart:23:9)
referred to by material: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/material.dart:21:9)
referred to by painting: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/painting.dart:18:9)
referred to by rendering: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/rendering.dart:22:9)
referred to by widgets: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/widgets.dart:13:9)
...
error: private API of package:Dart is reexported by libraries in other packages:
from services.ByteData: (file:///C:/Users/alfon/repos/flutter/bin/cache/pkg/sky_engine/lib/typed_data/typed_data.dart:424:16)
referred to by services: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/services.dart:11:9)
error: private API of package:Dart is reexported by libraries in other packages:
from services.ByteData.ByteData: (file:///C:/Users/alfon/repos/flutter/bin/cache/pkg/sky_engine/lib/typed_data/typed_data.dart:428:20)
referred to by services: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/services.dart:11:9)
error: private API of package:Dart is reexported by libraries in other packages:
from services.ByteData.view: (file:///C:/Users/alfon/repos/flutter/bin/cache/pkg/sky_engine/lib/typed_data/typed_data.dart:459:20)
referred to by services: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/services.dart:11:9)
error: private API of package:Dart is reexported by libraries in other packages:
from services.ByteData.sublistView: (file:///C:/Users/alfon/repos/flutter/bin/cache/pkg/sky_engine/lib/typed_data/typed_data.dart:481:20)
referred to by services: (file:///c:/users/alfon/repos/flutter/packages/flutter/lib/services.dart:11:9)
-
dartdoc 5.0.1 (/C:/Users/alfon/repos/DartToFableBindings/bin/fsgen.dart) failed: Command executables must exist. The file "c:\users\alfon\repos\flutter\bin\cache\dart-sdk\bin\dart" does not exist for tool snippet..
Did you manage to run the fsgen from the flutter repo? Can you help? π
Flutter is somewhat unique. They generate a dummy pubspec to make it compatible with dartdoc. Maybe you can get some output by creating a dummy empty flutter project that depends only on flutter and generating all bindings using it as a base.
You're right, that worked! Now I've a ton of bindings... I only need to make them compile π Getting excited now!
I'm gonna take a stab at getting that code generator to produce translations for function types. I'm using @alfonsogarciacaro's latest changes to the generator and it seems like functions are still not being translated. Correct me if I'm wrong on that, and I'm open to suggestions if anyone already has ideas.
Thanks a lot for your help @bentok! I think my latest changes are in this branch: https://github.com/alfonsogarciacaro/DartToFableBindings/tree/material-widgets
I was making several attempts and also did some manual changes. I think this code can output the module functions, but in any case the generator is a bit dirty at the moment, so some cleanup would be much appreciated. See the comment from @Nhowka about the dummy project necessary to make the doc generator work π https://github.com/alfonsogarciacaro/DartToFableBindings/blob/f001c9621d018a082a37cd593745d7549d33f72c/lib/fsgen.dart#L358-L361
Flutter is somewhat unique. They generate a dummy pubspec to make it compatible with dartdoc. Maybe you can get some output by creating a dummy empty flutter project that depends only on flutter and generating all bindings using it as a base.
@Nhowka do you think generating bindings for 3rd party Flutter libraries would require the same approach? I have made some modifications to both your code and @alfonsogarciacaro's fork (https://github.com/alfonsogarciacaro/DartToFableBindings/tree/material-widgets) and am getting close, but can't quite get it right.
For example, if I generate bindings for flutter_secure_storage, it will generate dozens of files - some of which have only a few bindings and others that have more. However it doesn't seem like any of the files have all of the bindings.
@bentok, I believe that for typical packages with standard pubspec files, the same surface outputted on their dartdoc documentation on pub.dev should be available to us. Could there be some filter pruning some of those before they reach the code generation stage?
If I'm not mistaken, we could generate bindings for them without using a dummy project, but it could be amazing if we could create bindings for all packages an actual project is referencing on the fly. We could have a cache, so we skip generating for known versions, but as dart has the advantage that the libraries are packaged with raw code that dartdoc could read, I believe it is an achievable goal.
Hey, l've come late to this thread, but @bentok and I have connected to start working on this again. I'm able to reproduce everything up to @alfonsogarciacaro getting errors on his first try to run this. But I have not yet worked out what to do once the empty flutter project is set up to get the bindings. I know it's been more than a year, but if someone remember and can give the exact step that would speed up the work a bit.
Hi everyone, I got the source code from https://github.com/alfonsogarciacaro/fable-flutterapp and after updating fable it compiled and ran correctly, but the auto/hot-reload does not work. Is there something that can be done to make this work?
I'm using vscode under Windows 10. Thank you.
Hello,
in the readme of the repo there is a mention that you have to trigger hot reload manually.
Did you give it a try ?
I never used Flutter so I donβt know if there is some requirements like in JavaScript for it to work.
Hi, I had not tried the "Ctr+F5" that works, I was just manually updating the .dart generated file to trigger the hot reload. But my question was more in regard to what is the missing/link/configuration the 'build.cmd' is running fable in watch mode so when you update the source code it creates the .dart file(s) and vscode does load the updated .dart file(s) and like I said I was manually updating the .dart file to manual trigger hot reload hence my question is why if vscode 'knows' the file has changed the hot reload is not triggered.
Thank you.
Hello @octaviordz,
I am not sure I understood everything because it was a really long sentence π
But, the first thing I was check is what is the behaviour of hot reload in a pure Dart project because if the behaviour is the same then there is nothing that can be improve.
If not, then someone with Dart/Flutter knowledge will need to have a look at it.
Hi @MangelMaxime, Hot reload works in a pure Dart project as expected. Thank you for your response.
Has this been abandoned? I just forked the repo and updated the dependencies but it looks like there is still a lot of work to get this into a usable state. Did you get anywhere with generating the class members?
@endeavour The main developer for Dart target is not active anymore.
If someone want to step in to contribute to it, we welcome contributors.
I think we discussed it before but it'll be nice to have a semi-automatic way to generate Dart/Flutter bindings so users can start writing apps when the compiler is ready, so I'm opening this issue for discussion.
I've uploaded a dead-simple Elmish Flutter app here: https://github.com/alfonsogarciacaro/fable-flutterapp
I manually wrote a few bindings for the things I needed in this file. In general, bindings are very similar to the JS ones, there's some discussion about writing bindings in general for Snake Island in #2779. A couple of specifics for Dart:
NamedParams
attribute: used to indicate the method has named params in Dart. If the named params start from the 2nd or 3rd argument you can passfromIndex
(zero based) as in[<NamedParams(fromIndex=1)>]
IsConst
indicates the method (or constructor in the case of classes) should be called withconst
if all arguments are constantsIdeally the bindings should be extracted from this repo. In previous conversations @Nhowka commented there are introspection tools for Dart so maybe we could use those, or is it simpler to just write a simple custom parser? Pinging also @adelarsq who also has experience with Dart and @davedawkins because he's good at writing scripts for code generation as he did with the Feliz API πΌ