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