Skip to content

Commit

Permalink
rfw2txt without format output
Browse files Browse the repository at this point in the history
  • Loading branch information
ebwood committed Mar 9, 2024
1 parent 8a3a7d7 commit 91a1404
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 13 deletions.
2 changes: 1 addition & 1 deletion packages/rfw2txt/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
## 1.0.0
## 0.0.1

- Initial version.
2 changes: 1 addition & 1 deletion packages/rfw2txt/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
A sample command-line application providing basic argument parsing with an entrypoint in `bin/`.
# rfw2txt
116 changes: 114 additions & 2 deletions packages/rfw2txt/bin/rfw2txt.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void main(List<String> arguments) {
printUsage(argParser);
return;
}

// check if file exists
String rfwPath = results.arguments[0];
File rfwFile = File(rfwPath);
Expand All @@ -81,11 +81,123 @@ void main(List<String> arguments) {
}
File outputFile = File(outputPath);
outputFile.writeAsStringSync(
decodeLibraryBlob(rfwFile.readAsBytesSync()).toString());
decodeLibraryBlob(rfwFile.readAsBytesSync()).visit(ParseTxtVisitor()));
} on FormatException catch (e) {
// Print usage information if an invalid argument was provided.
print(e.message);
print('');
printUsage(argParser);
}
}

extension on RemoteWidgetLibrary {
String visit(ParseTxtVisitor visitor) => visitor.visit(this);
}

class ParseTxtVisitor {
String visit(RemoteWidgetLibrary library) {
StringBuffer buffer = StringBuffer();
// write imports
buffer.writeln(library.imports.map(_visitImport).join('\n'));

buffer.writeln();
// write widget declarations
for (var element in library.widgets) {
buffer.writeln(_visitWidgetDeclaration(element));
}
return buffer.toString();
}

// visit import
String _visitImport(Import import) => 'import ${import.name};';

// visit widget declaration
String _visitWidgetDeclaration(WidgetDeclaration widget) {
StringBuffer buffer = StringBuffer();
buffer.write('widget ${widget.name}');

if (widget.initialState != null) {
buffer.write(_visitDynamicMap(widget.initialState!));
}

buffer.write(' = ');
buffer.write(_visitObject(widget.root));
buffer.write(';');
return buffer.toString();
}

// visit DynamicMap
String _visitDynamicMap(DynamicMap map, {bool withoutCurlyBraces = false}) {
StringBuffer buffer = StringBuffer();

DynamicMap newMap = map.map((key, value) {
if (value is int && key == 'color') {
return MapEntry(key, int2Color(value));
}
return MapEntry(key, _visitObject(value, dynamicMapKey: key));
});

if (withoutCurlyBraces) {
buffer
.write(newMap.entries.map((e) => '${e.key}: ${e.value}').join(', '));
} else {
buffer.write(newMap);
}
return buffer.toString();
}

// visit DynamicList
String _visitDynamicList(DynamicList list) =>
list.map((e) => _visitObject(e)).toList().toString();

// visit BlobNode
String _visitBlobNode(BlobNode node) {
StringBuffer buffer = StringBuffer();
if (node is ConstructorCall) {
// ConstructorCall ignore arguments' curly braces
buffer.write('${node.name}(');
buffer.write(_visitDynamicMap(node.arguments, withoutCurlyBraces: true));
buffer.write(')');
} else if (node is Switch) {
buffer.write('switch ');
buffer.write(_visitObject(node.input));
buffer.write(' ');
node.outputs.forEach((key, value) {});
// TODO: Can key be another type?
buffer.write(node.outputs.map((key, value) => MapEntry(
key == null ? 'default' : '$key',
_visitObject(value, dynamicMapKey: '$key'))));
} else if (node is EventHandler) {
buffer.write('event "${node.eventName}" ');
buffer.write(_visitDynamicMap(node.eventArguments));
} else {
buffer.write(node.toString());
}
return buffer.toString();
}

// BlobNode, DynamicMap, DynamicList, int, double, bool, String, null
String _visitObject(Object? object, {String? dynamicMapKey}) {
if (object is BlobNode) {
return _visitBlobNode(object);
} else if (object is DynamicMap) {
return _visitDynamicMap(object);
} else if (object is DynamicList) {
if (object.every((element) => element is int) &&
dynamicMapKey == 'colors') {
return object.map((e) => int2Color(e as int)).toList().toString();
}
return _visitDynamicList(object);
}
if (object is String) {
return '"$object"';
} else {
//int, double, bool, null
return '$object';
}
}

String int2Color(int value) {
return '0x${value.toRadixString(16).toUpperCase().toUpperCase()}';
}
}
7 changes: 3 additions & 4 deletions packages/rfw2txt/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,9 @@ packages:
rfw:
dependency: "direct main"
description:
name: rfw
sha256: ae96afb1c345f53239c5ab3222cff94896df511ca4a53b2fcec5c64678cbb2ff
url: "https://pub.dev"
source: hosted
path: "../../../rfw-1.0.24"
relative: true
source: path
version: "1.0.24"
shelf:
dependency: transitive
Expand Down
3 changes: 2 additions & 1 deletion packages/rfw2txt/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ executables:
dependencies:
args: ^2.4.2
path: ^1.9.0
rfw: ^1.0.24
rfw:
path: ../../../rfw-1.0.24

dev_dependencies:
lints: ^3.0.0
Expand Down
59 changes: 59 additions & 0 deletions packages/rfw2txt/test/match.rfwtxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import core.widgets;
import core.material;

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,
),
),
);
50 changes: 46 additions & 4 deletions packages/rfw2txt/test/rfw2txt_test.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,50 @@
import 'package:test/expect.dart';
import 'package:test/scaffolding.dart';
@TestOn('vm')
import 'dart:convert';
import 'dart:io';

import 'package:rfw/formats.dart';
import 'package:test/test.dart';
import 'package:collection/collection.dart';

void main() {
test('rfw2txt', () {
expect(1, 2);
test('rfw2txt without output path', () async {
Process process = await Process.start(
'dart', ['run', 'bin/rfw2txt.dart', "test/test.rfw"]);
await process.stdout.transform(utf8.decoder).forEach(print);
await process.stderr.transform(utf8.decoder).forEach(print);
File matchFile = File('test/test.rfw');
File outputTxtFile = File('test.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', "test/test.rfw", "-o", "test.rfwtxt"]);
await process.stdout.transform(utf8.decoder).forEach(print);
await process.stderr.transform(utf8.decoder).forEach(print);
File matchFile = File('test/test.rfw');
File outputTxtFile = File('test.rfwtxt');
File outputFile = File('output.rfw');
outputFile.writeAsBytesSync(
encodeLibraryBlob(parseLibraryFile(outputTxtFile.readAsStringSync())));
expect(outputFile.existsSync(), true);
expect(
ListEquality()
.equals(matchFile.readAsBytesSync(), matchFile.readAsBytesSync()),
true);

outputFile.delete();
outputTxtFile.delete();
});
}
Binary file added packages/rfw2txt/test/test.rfw
Binary file not shown.

0 comments on commit 91a1404

Please sign in to comment.