diff --git a/melos.yaml b/melos.yaml index 6c28c13..8aa5085 100644 --- a/melos.yaml +++ b/melos.yaml @@ -5,7 +5,7 @@ packages: - packages/rfw2txt - packages/widget2rfw - packages/rfw_builder - - packages/rfw_tools + - packages/rfw_txt scripts: add_sort: diff --git a/packages/rfw_tools/bin/rfw2txt.dart b/packages/rfw_tools/bin/rfw2txt.dart deleted file mode 100644 index 91c17c5..0000000 --- a/packages/rfw_tools/bin/rfw2txt.dart +++ /dev/null @@ -1,3 +0,0 @@ -void main() { - print('rfw2txt cli'); -} diff --git a/packages/rfw_tools/bin/txt2rfw.dart b/packages/rfw_tools/bin/txt2rfw.dart deleted file mode 100644 index 82e85cf..0000000 --- a/packages/rfw_tools/bin/txt2rfw.dart +++ /dev/null @@ -1,3 +0,0 @@ -void main() { - print('txt2rfw cli'); -} diff --git a/packages/rfw_tools/lib/rfw_tools.dart b/packages/rfw_tools/lib/rfw_tools.dart deleted file mode 100644 index e69de29..0000000 diff --git a/packages/rfw_tools/melos_rfw_tools.iml b/packages/rfw_tools/melos_rfw_tools.iml deleted file mode 100644 index 389d07a..0000000 --- a/packages/rfw_tools/melos_rfw_tools.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/rfw_tools/pubspec.yaml b/packages/rfw_tools/pubspec.yaml deleted file mode 100644 index a177e4c..0000000 --- a/packages/rfw_tools/pubspec.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: rfw_tools -description: A sample command-line application with basic argument parsing. -version: 0.0.1 -# repository: https://github.com/my_org/my_repo - -environment: - sdk: ^3.2.0 - -executables: - rfw2txt: - txt2rfw: - -# Add regular dependencies here. -dependencies: - args: ^2.4.2 - -dev_dependencies: - import_sorter: ^4.6.0 - lints: ^3.0.0 - test: ^1.24.0 diff --git a/packages/rfw_tools/test/rfw_tools_test.dart b/packages/rfw_tools/test/rfw_tools_test.dart deleted file mode 100644 index ebaf28a..0000000 --- a/packages/rfw_tools/test/rfw_tools_test.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:test/test.dart'; - -void main() { - test('rfw_tools', () { - expect(1, 1); - }); -} diff --git a/packages/rfw_tools/.gitignore b/packages/rfw_txt/.gitignore similarity index 100% rename from packages/rfw_tools/.gitignore rename to packages/rfw_txt/.gitignore diff --git a/packages/rfw_tools/CHANGELOG.md b/packages/rfw_txt/CHANGELOG.md similarity index 100% rename from packages/rfw_tools/CHANGELOG.md rename to packages/rfw_txt/CHANGELOG.md diff --git a/packages/rfw_tools/README.md b/packages/rfw_txt/README.md similarity index 100% rename from packages/rfw_tools/README.md rename to packages/rfw_txt/README.md diff --git a/packages/rfw_tools/analysis_options.yaml b/packages/rfw_txt/analysis_options.yaml similarity index 100% rename from packages/rfw_tools/analysis_options.yaml rename to packages/rfw_txt/analysis_options.yaml diff --git a/packages/rfw_txt/bin/rfw2txt.dart b/packages/rfw_txt/bin/rfw2txt.dart new file mode 100644 index 0000000..fb60795 --- /dev/null +++ b/packages/rfw_txt/bin/rfw2txt.dart @@ -0,0 +1,96 @@ +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:path/path.dart'; +import 'package:yaml/yaml.dart'; + +import 'package:rfw_txt/src/rfw2txt.dart'; + +ArgParser buildParser() { + return ArgParser() + ..addFlag( + 'help', + abbr: 'h', + negatable: false, + help: 'Print this usage information.', + ) + ..addFlag( + 'verbose', + negatable: false, + help: 'Show additional command output.', + ) + ..addFlag( + 'version', + abbr: 'v', + negatable: false, + help: 'Print the tool version.', + ) + ..addOption('output', abbr: 'o', help: 'Output path.'); +} + +void printUsage(ArgParser argParser) { + print('Usage: rfw2txt [arguments]'); + print(argParser.usage); +} + +void main(List arguments) { + final ArgParser argParser = buildParser(); + try { + final ArgResults results = argParser.parse(arguments); + bool verbose = false; + + // Process the parsed arguments. + if (results.wasParsed('help')) { + printUsage(argParser); + return; + } + if (results.wasParsed('version')) { + String version = '0.0.1'; + try { + File pubspecFile = File('pubspec.yaml'); + version = loadYaml(pubspecFile.readAsStringSync())['version']; + } catch (e) { + print(e); + } + + print('rfw2txt version: $version'); + return; + } + if (results.wasParsed('verbose')) { + verbose = true; + } + + if (verbose) { + print('[VERBOSE] All arguments: ${results.arguments}'); + } + + String outputPath = ''; + if (results.wasParsed('output')) { + outputPath = results['output'] as String; + } + + if (results.arguments.isEmpty) { + print('No rfw path provided.'); + printUsage(argParser); + return; + } + + // check if file exists + String rfwPath = results.arguments[0]; + File rfwFile = File(rfwPath); + if (!rfwFile.existsSync()) { + print('File not found: $rfwPath'); + return; + } + + if (outputPath.isEmpty) { + outputPath = '${basenameWithoutExtension(rfwPath)}.rfwtxt'; + } + File outputFile = File(outputPath); + outputFile.writeAsStringSync(rfw2txt(rfwFile.readAsBytesSync())); + } on FormatException catch (e) { + // Print usage information if an invalid argument was provided. + print(e.message); + printUsage(argParser); + } +} diff --git a/packages/rfw_tools/bin/rfw_tools.dart b/packages/rfw_txt/bin/txt2rfw.dart similarity index 51% rename from packages/rfw_tools/bin/rfw_tools.dart rename to packages/rfw_txt/bin/txt2rfw.dart index 0a2eb30..9e472e5 100644 --- a/packages/rfw_tools/bin/rfw_tools.dart +++ b/packages/rfw_txt/bin/txt2rfw.dart @@ -1,6 +1,10 @@ +import 'dart:io'; + import 'package:args/args.dart'; +import 'package:path/path.dart'; +import 'package:yaml/yaml.dart'; -const String version = '0.0.1'; +import 'package:rfw_txt/src/txt2rfw.dart'; ArgParser buildParser() { return ArgParser() @@ -20,11 +24,12 @@ ArgParser buildParser() { 'version', negatable: false, help: 'Print the tool version.', - ); + ) + ..addOption('output', abbr: 'o', help: 'Output path.'); } void printUsage(ArgParser argParser) { - print('Usage: dart rfw_tools.dart [arguments]'); + print('Usage: txt2rfw [arguments]'); print(argParser.usage); } @@ -40,22 +45,55 @@ void main(List arguments) { return; } if (results.wasParsed('version')) { - print('rfw_tools version: $version'); + String version = '0.0.1'; + try { + File pubspecFile = File('pubspec.yaml'); + version = loadYaml(pubspecFile.readAsStringSync())['version']; + } catch (e) { + print(e); + } + + print('rfw2txt version: $version'); return; } + if (results.wasParsed('verbose')) { verbose = true; } // Act on the arguments provided. - print('Positional arguments: ${results.rest}'); if (verbose) { print('[VERBOSE] All arguments: ${results.arguments}'); } + + String outputPath = ''; + if (results.wasParsed('output')) { + outputPath = results['output'] as String; + } + + if (results.arguments.isEmpty) { + print('No rfwtxt path provided.'); + printUsage(argParser); + return; + } + + // check if file exists + String txtPath = results.arguments[0]; + File txtFile = File(txtPath); + if (!txtFile.existsSync()) { + print('File not found: $txtPath'); + return; + } + + if (outputPath.isEmpty) { + outputPath = '${basenameWithoutExtension(txtPath)}.rfw'; + } + File outputFile = File(outputPath); + + outputFile.writeAsBytesSync(txt2rfw(txtFile.readAsStringSync())); } on FormatException catch (e) { // Print usage information if an invalid argument was provided. print(e.message); - print(''); printUsage(argParser); } } diff --git a/packages/rfw_txt/data/test1.rfw b/packages/rfw_txt/data/test1.rfw new file mode 100644 index 0000000..349667d Binary files /dev/null and b/packages/rfw_txt/data/test1.rfw differ diff --git a/packages/rfw_txt/data/test1.rfwtxt b/packages/rfw_txt/data/test1.rfwtxt new file mode 100644 index 0000000..a02fa0a --- /dev/null +++ b/packages/rfw_txt/data/test1.rfwtxt @@ -0,0 +1,14 @@ +import core.widgets; +import core.material; + +widget hello = Scaffold( + appBar: AppBar(title: Text(text: "Hello Demo")), + body: Container( + height: 100, + color: 0xFF00FF00, + child: Center( + child: Text(text: ["Hello, ", data.greet.name, '!'], textDirection: "ltr", style: { + color: 0xFFFF0000 + }), + ), +)); \ No newline at end of file diff --git a/packages/rfw_txt/data/test2.rfw b/packages/rfw_txt/data/test2.rfw new file mode 100644 index 0000000..9c6242c Binary files /dev/null and b/packages/rfw_txt/data/test2.rfw differ diff --git a/packages/rfw_txt/data/test2.rfwtxt b/packages/rfw_txt/data/test2.rfwtxt new file mode 100644 index 0000000..c880d98 --- /dev/null +++ b/packages/rfw_txt/data/test2.rfwtxt @@ -0,0 +1,61 @@ +import core.widgets; +import core.material; + +widget Empty = Container(); + +widget Counter = Container( + color: 0xFF66AACC, + child: Center( + child: Button( + child: Padding( + padding: [ 20.0 ], + child: Text(text: data.counter, style: { + fontSize: 56.0, + color: 0xFF000000, + }), + ), + onPressed: event "increment" { }, + ), + ), +); + +widget Button { down: false } = GestureDetector( + onTap: args.onPressed, + onTapDown: set state.down = true, + onTapUp: set state.down = false, + onTapCancel: set state.down = false, + child: Container( + duration: 50, + margin: switch state.down { + false: [ 0.0, 0.0, 2.0, 2.0 ], + true: [ 2.0, 2.0, 0.0, 0.0 ], + }, + padding: [ 12.0, 8.0 ], + decoration: { + type: "shape", + shape: { + type: "stadium", + side: { width: 1.0 }, + }, + gradient: { + type: "linear", + begin: { x: -0.5, y: -0.25 }, + end: { x: 0.0, y: 0.5 }, + colors: [ 0xFFFFFF99, 0xFFEEDD00 ], + stops: [ 0.0, 1.0 ], + tileMode: "mirror", + }, + shadows: switch state.down { + false: [ { blurRadius: 4.0, spreadRadius: 0.5, offset: { x: 1.0, y: 1.0, } } ], + default: [], + }, + }, + child: DefaultTextStyle( + style: { + color: 0xFF000000, + fontSize: 32.0, + }, + child: args.child, + ), + ), +); diff --git a/packages/rfw_txt/lib/rfw_txt.dart b/packages/rfw_txt/lib/rfw_txt.dart new file mode 100644 index 0000000..21d57c5 --- /dev/null +++ b/packages/rfw_txt/lib/rfw_txt.dart @@ -0,0 +1,3 @@ +library rfw_txt; + +export 'src/txt2rfw.dart'; diff --git a/packages/rfw_txt/lib/src/rfw2txt.dart b/packages/rfw_txt/lib/src/rfw2txt.dart new file mode 100644 index 0000000..0b94077 --- /dev/null +++ b/packages/rfw_txt/lib/src/rfw2txt.dart @@ -0,0 +1,25 @@ +import 'dart:typed_data'; + +import 'package:collection/collection.dart'; +import 'package:rfw/formats.dart'; + +import 'rwl2json.dart'; +import 'rwl2txt.dart'; + +// Parse .rfw to .rfwtxt +String rfw2txt(Uint8List bytes) { + RemoteWidgetLibrary rwl = decodeLibraryBlob(bytes); + String output = rwl2txt(rwl); + if (ListEquality() + .equals(bytes, encodeLibraryBlob(parseLibraryFile(output))) == + false) { + throw Exception('rfw2txt failed'); + } + return output; +} + +// Parse .rfw to json +Map rfw2json(Uint8List bytes) { + RemoteWidgetLibrary rwl = decodeLibraryBlob(bytes); + return rwl2json(rwl); +} diff --git a/packages/rfw_txt/lib/src/rwl2json.dart b/packages/rfw_txt/lib/src/rwl2json.dart new file mode 100644 index 0000000..8a9d2e5 --- /dev/null +++ b/packages/rfw_txt/lib/src/rwl2json.dart @@ -0,0 +1,117 @@ +import 'package:rfw/formats.dart'; + +// Parse RemoteWidgetLibrary to json +Map rwl2json(RemoteWidgetLibrary library) { + return JsonVisitor().visit(library); +} + +// RemoteWidgetLibrary to json visitor +class JsonVisitor { + Map visit(RemoteWidgetLibrary library) { + return { + 'type': '$runtimeType', + 'imports': library.imports.map((e) => _visitImport(e)).toList(), + 'widgets': + library.widgets.map((e) => _visitWidgetDeclaration(e)).toList(), + }; + } + + String _visitImport(Import import) => 'import ${import.name}'; + + Map _visitWidgetDeclaration(WidgetDeclaration declaration) { + return { + 'name': declaration.name, + 'type': '${declaration.runtimeType}', + 'root': _visitBlobNode(declaration.root), + }; + } + + Map _visitBlobNode(BlobNode node) { + if (node is WidgetDeclaration) { + return _visitWidgetDeclaration(node); + } else if (node is ConstructorCall) { + return _visitConstructorCall(node); + } else if (node is Reference) { + return _visitReference(node); + } else if (node is AnyEventHandler) { + return _visitAnyEventHandler(node); + } else if (node is Switch) { + return _visitSwitch(node); + } else { + return { + 'type': '$runtimeType', + }; + } + } + + Map _visitConstructorCall(ConstructorCall call) { + return { + 'type': '${call.runtimeType}', + 'name': call.name, + 'arguments': _visitDynamicMap(call.arguments), + }; + } + + Map _visitReference(Reference reference) { + return {'type': '${reference.runtimeType}', 'parts': reference.toString()}; + } + + Map _visitSwitch(Switch sw) { + return { + 'type': '${sw.runtimeType}', + 'input': _visitObject(sw.input), + 'outputs': sw.outputs.map((key, value) => + MapEntry(key == null ? 'default' : '$key', _visitObject(value))), + }; + } + + List _visitDynamicList(DynamicList list) { + return list.map((e) => _visitObject(e)).toList(); + } + + Map _visitDynamicMap(DynamicMap map) { + return map.map((key, value) { + if (value is DynamicList) { + return MapEntry(key, _visitObject(value)); + } + return MapEntry(key, _visitObject(value)); + }); + } + + Map _visitAnyEventHandler(AnyEventHandler handler) { + if (handler is EventHandler) { + return { + 'type': '${handler.runtimeType}', + 'eventName': handler.eventName, + 'eventArguments': _visitDynamicMap(handler.eventArguments), + }; + } else if (handler is SetStateHandler) { + return { + 'type': '${handler.runtimeType}', + 'stateReference': _visitReference(handler.stateReference), + 'value': _visitObject(handler.value), + }; + } + return { + 'type': '${handler.runtimeType}', + }; + } + + dynamic _visitObject(Object? e) { + if (e is BlobNode) { + return _visitBlobNode(e); + } else if (e is DynamicMap) { + return _visitDynamicMap(e); + } else if (e is DynamicList) { + return _visitDynamicList(e); + } + return { + 'type': '${e.runtimeType}', + 'value': e, + }; + } + + String int2Color(int value) { + return '0x${value.toRadixString(16).toUpperCase().toUpperCase()}'; + } +} diff --git a/packages/rfw_txt/lib/src/rwl2txt.dart b/packages/rfw_txt/lib/src/rwl2txt.dart new file mode 100644 index 0000000..584a58e --- /dev/null +++ b/packages/rfw_txt/lib/src/rwl2txt.dart @@ -0,0 +1,172 @@ +import 'package:collection/collection.dart'; +import 'package:rfw/formats.dart'; + +// Parse RemoteWidgetLibrary to .rfwtxt +String rwl2txt(RemoteWidgetLibrary library) { + return TxtVisitor().visit(library); +} + +// int color to raw hex, should ignore quote for output +class ColorValue { + final String color; + ColorValue(this.color); + + @override + String toString() => color; +} + +// RemoteWidgetLibrary to .rfwtxt format visitor +class TxtVisitor { + final String _indent = ' '; + int _indentCount = 0; + + String get _leadingIndent => _indent * _indentCount; + + String visit(RemoteWidgetLibrary library) { + StringBuffer buffer = StringBuffer(); + // write imports + for (var element in library.imports) { + _visitImport(element, buffer); + } + + buffer.write('\n'); + // write widget declarations + for (var element in library.widgets) { + _visitWidgetDeclaration(element, buffer); + } + return buffer.toString(); + } + +// visit import + void _visitImport(Import import, StringBuffer buffer) { + buffer.write('import ${import.name};\n'); + } + +// visit widget declaration + void _visitWidgetDeclaration(WidgetDeclaration widget, StringBuffer buffer) { + buffer.write('widget ${widget.name}'); + + if (widget.initialState != null) { + buffer.write(' '); + _visitDynamicMap(widget.initialState!, buffer, singleLine: true); + } + + buffer.write(' = '); + _visitObject(widget.root, buffer); + buffer.write(';\n\n'); + } + +// visit DynamicMap + void _visitDynamicMap(DynamicMap map, StringBuffer buffer, + {bool withoutCurlyBraces = false, bool singleLine = false}) { + if (map.isEmpty) { + buffer.write(withoutCurlyBraces ? '' : '{ }'); + return; + } + + // convert int/list to color format, like 0x00FF0000 + map = map.map((key, value) { + if (value is int && key == 'color') { + return MapEntry(key, _int2Color(value)); + } + if (value is DynamicList && + value.every((element) => element is int) && + key == 'colors') { + return MapEntry(key, value.map((e) => _int2Color(e as int)).toList()); + } + return MapEntry(key, value); + }); + + _indentCount++; + if (!withoutCurlyBraces) { + buffer.write('{'); + if (singleLine) buffer.write(' '); + } + // if (map.length == 1) { + // buffer.write('${map.entries.first.key}: '); + // _visitObject(map.entries.first.value, buffer); + // buffer.write(' '); + // } else { + if (!singleLine) buffer.write('\n'); + + for (var (index, MapEntry(:key, :value)) in map.entries.indexed) { + if (!singleLine) buffer.write(_leadingIndent); + buffer.write('$key: '); + _visitObject(value, buffer); + if (index != map.length - 1 || !singleLine) buffer.write(','); + if (!singleLine) buffer.write('\n'); + } + // } + _indentCount--; + // if (map.length > 1) { + buffer.write(_leadingIndent); + // } + if (!withoutCurlyBraces) { + if (singleLine) buffer.write(' '); + buffer.write('}'); + } + } + +// visit DynamicList + void _visitDynamicList(DynamicList list, StringBuffer buffer) { + buffer.write('['); + list.forEachIndexed((index, element) { + buffer.write(' '); + _visitObject(element, buffer); + if (index != list.length - 1) { + buffer.write(','); + } else { + buffer.write(' '); + } + }); + buffer.write(']'); + } + +// visit BlobNode + void _visitBlobNode(BlobNode node, StringBuffer buffer) { + if (node is ConstructorCall) { + // ConstructorCall ignore arguments' curly braces + buffer.write('${node.name}('); + if (node.arguments.isNotEmpty) { + _visitDynamicMap(node.arguments, buffer, withoutCurlyBraces: true); + // buffer.write(_leadingIndent); + } + buffer.write(')'); + } else if (node is Switch) { + buffer.write('switch '); + _visitObject(node.input, buffer); + buffer.write(' '); + // TODO: Can key be another type? + _visitDynamicMap( + node.outputs.map((key, value) => + MapEntry(key == null ? 'default' : '$key', value)), + buffer); + } else if (node is EventHandler) { + buffer.write('event "${node.eventName}" '); + _visitDynamicMap(node.eventArguments, buffer); + } else { + buffer.write(node.toString()); + } + } + +// BlobNode, DynamicMap, DynamicList, int, double, bool, String, null + void _visitObject(Object? object, StringBuffer buffer) { + if (object is BlobNode) { + return _visitBlobNode(object, buffer); + } else if (object is DynamicMap) { + return _visitDynamicMap(object, buffer); + } else if (object is DynamicList) { + return _visitDynamicList(object, buffer); + } else if (object is String) { + return buffer.write('"$object"'); + } else { + //int, double, bool, null + return buffer.write(object); + } + } + + ColorValue _int2Color(int value) { + return ColorValue( + '0x${value.toRadixString(16).toUpperCase().toUpperCase()}'); + } +} diff --git a/packages/rfw_txt/lib/src/txt2rfw.dart b/packages/rfw_txt/lib/src/txt2rfw.dart new file mode 100644 index 0000000..b35cae1 --- /dev/null +++ b/packages/rfw_txt/lib/src/txt2rfw.dart @@ -0,0 +1,13 @@ +import 'dart:typed_data'; + +import 'package:rfw/formats.dart'; + +// Parse .rfwtxt format to .rfw format +Uint8List txt2rfw(String txt) { + return encodeLibraryBlob(txt2rfl(txt)); +} + +// Parse .rfwtxt to RemoteWidgetLibrary +RemoteWidgetLibrary txt2rfl(String txt) { + return parseLibraryFile(txt); +} diff --git a/packages/rfw_tools/pubspec.lock b/packages/rfw_txt/pubspec.lock similarity index 89% rename from packages/rfw_tools/pubspec.lock rename to packages/rfw_txt/pubspec.lock index ee678a9..b91e661 100644 --- a/packages/rfw_tools/pubspec.lock +++ b/packages/rfw_txt/pubspec.lock @@ -41,8 +41,16 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" - collection: + characters: dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + collection: + dependency: "direct main" description: name: collection sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a @@ -81,6 +89,11 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + flutter: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" frontend_server_client: dependency: transitive description: @@ -161,14 +174,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.0" mime: dependency: transitive description: @@ -194,7 +215,7 @@ packages: source: hosted version: "2.1.0" path: - dependency: transitive + dependency: "direct main" description: name: path sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" @@ -217,6 +238,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + rfw: + dependency: "direct main" + description: + name: rfw + sha256: "079eb640f510b2b0e606dd011e6ccf438d39def206133bca400ba19bc0074667" + url: "https://pub.dev" + source: hosted + version: "1.0.26" shelf: dependency: transitive description: @@ -249,6 +278,11 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" source_map_stack_trace: dependency: transitive description: @@ -345,6 +379,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" vm_service: dependency: transitive description: @@ -386,7 +428,7 @@ packages: source: hosted version: "1.2.1" yaml: - dependency: transitive + dependency: "direct main" description: name: yaml sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" @@ -394,4 +436,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.3.1 <4.0.0" + flutter: ">=3.16.0" diff --git a/packages/rfw_txt/pubspec.yaml b/packages/rfw_txt/pubspec.yaml new file mode 100644 index 0000000..7010998 --- /dev/null +++ b/packages/rfw_txt/pubspec.yaml @@ -0,0 +1,21 @@ +name: rfw_txt +description: | + A tool for converting between .rfw and .rfwtxt formats, including the intermediate class RemoteWidgetLibrary +version: 0.0.1 +repository: https://github.com/ebwood/rfwt + +environment: + sdk: ^3.3.1 + +# Add regular dependencies here. +dependencies: + args: ^2.4.2 + collection: ^1.18.0 + path: ^1.9.0 + rfw: ^1.0.26 + yaml: ^3.1.2 + +dev_dependencies: + import_sorter: ^4.6.0 + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/rfw_txt/test/rfw2txt_test.dart b/packages/rfw_txt/test/rfw2txt_test.dart new file mode 100644 index 0000000..a336bd8 --- /dev/null +++ b/packages/rfw_txt/test/rfw2txt_test.dart @@ -0,0 +1,51 @@ +@TestOn('vm') + +import 'dart:convert'; +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:rfw/formats.dart'; +import 'package:test/test.dart'; + +void main() { + test('rfw2txt without output path', () async { + Process process = await Process.start( + 'dart', ['run', 'bin/rfw2txt.dart', "data/test1.rfw"]); + await process.stdout.transform(utf8.decoder).forEach(print); + await process.stderr.transform(utf8.decoder).forEach(print); + File matchFile = File('data/test1.rfw'); + File outputTxtFile = File('test1.rfwtxt'); + File outputFile = File('output.rfw'); + outputFile.writeAsBytesSync( + encodeLibraryBlob(parseLibraryFile(outputTxtFile.readAsStringSync()))); + // use rfw encoder to convert output test.rfwtxt to test.rfw, then check the file is equal to test/test.rfw + expect(outputFile.existsSync(), true); + expect( + ListEquality() + .equals(matchFile.readAsBytesSync(), matchFile.readAsBytesSync()), + true); + + outputFile.delete(); + outputTxtFile.delete(); + }); + + test('rfw2txt with output path', () async { + Process process = await Process.start('dart', + ['run', 'bin/rfw2txt.dart', "data/test1.rfw", "-o", "test/output.rfwtxt"]); + await process.stdout.transform(utf8.decoder).forEach(print); + await process.stderr.transform(utf8.decoder).forEach(print); + File matchFile = File('data/test1.rfw'); + File outputTxtFile = File('test/output.rfwtxt'); + File outputFile = File('test/output.rfw'); + outputFile.writeAsBytesSync( + encodeLibraryBlob(parseLibraryFile(outputTxtFile.readAsStringSync()))); + expect(outputFile.existsSync(), true); + expect( + ListEquality() + .equals(matchFile.readAsBytesSync(), matchFile.readAsBytesSync()), + true); + + outputFile.delete(); + outputTxtFile.delete(); + }); +} diff --git a/packages/rfw_txt/test/txt2rfw_test.dart b/packages/rfw_txt/test/txt2rfw_test.dart new file mode 100644 index 0000000..254b0c0 --- /dev/null +++ b/packages/rfw_txt/test/txt2rfw_test.dart @@ -0,0 +1,41 @@ +@TestOn('vm') + +import 'dart:convert'; +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:test/test.dart'; + +void main() { + test('txt2rfw without output path', () async { + Process process = await Process.start( + 'dart', ['run', 'bin/txt2rfw.dart', "data/test1.rfwtxt"]); + await process.stdout.transform(utf8.decoder).forEach(print); + await process.stderr.transform(utf8.decoder).forEach(print); + File matchFile = File('data/test1.rfw'); + File outputFile = File('test1.rfw'); + expect(outputFile.existsSync(), true); + expect( + ListEquality() + .equals(matchFile.readAsBytesSync(), matchFile.readAsBytesSync()), + true); + + outputFile.delete(); + }); + + test('txt2rfw with output path', () async { + Process process = await Process.start('dart', + ['run', 'bin/txt2rfw.dart', "data/test2.rfwtxt", "-o", "test/output2.rfw"]); + await process.stdout.transform(utf8.decoder).forEach(print); + await process.stderr.transform(utf8.decoder).forEach(print); + File matchFile = File('data/test2.rfw'); + File outputFile = File('test/output2.rfw'); + expect(outputFile.existsSync(), true); + expect( + ListEquality() + .equals(matchFile.readAsBytesSync(), matchFile.readAsBytesSync()), + true); + + outputFile.delete(); + }); +} diff --git a/packages/rfw_txt/test2.rfw b/packages/rfw_txt/test2.rfw new file mode 100644 index 0000000..9c6242c Binary files /dev/null and b/packages/rfw_txt/test2.rfw differ