Unverified Commit 5a8de59a authored by Alexandre Ardhuin's avatar Alexandre Ardhuin Committed by GitHub

refactor generateString to emit simpler dart code (#49334)

parent 94210a66
...@@ -139,17 +139,17 @@ String _jsonToMap(dynamic json) { ...@@ -139,17 +139,17 @@ String _jsonToMap(dynamic json) {
if (json == null || json is num || json is bool) if (json == null || json is num || json is bool)
return '$json'; return '$json';
if (json is String) { if (json is String)
if (currentLocale == 'kn') return generateEncodedString(currentLocale, json);
return generateEncodedString(json);
else if (json.contains("'"))
return 'r"""$json"""';
else
return "r'''$json'''";
}
if (json is Iterable) if (json is Iterable) {
return '<dynamic>[${json.map<String>(_jsonToMap).join(',')}]'; final StringBuffer buffer = StringBuffer('<dynamic>[');
for (final dynamic value in json) {
buffer.writeln('${_jsonToMap(value)},');
}
buffer.write(']');
return buffer.toString();
}
if (json is Map<String, dynamic>) { if (json is Map<String, dynamic>) {
final StringBuffer buffer = StringBuffer('<String, dynamic>{'); final StringBuffer buffer = StringBuffer('<String, dynamic>{');
......
...@@ -464,10 +464,7 @@ String generateValue(String value, Map<String, dynamic> attributes, LocaleInfo l ...@@ -464,10 +464,7 @@ String generateValue(String value, Map<String, dynamic> attributes, LocaleInfo l
return _scriptCategoryToEnum[value]; return _scriptCategoryToEnum[value];
} }
} }
// Localization strings for the Kannada locale ('kn') are encoded because return generateEncodedString(locale.languageCode, value);
// some of the localized strings contain characters that can crash Emacs on Linux.
// See packages/flutter_localizations/lib/src/l10n/README for more information.
return locale.languageCode == 'kn' ? generateEncodedString(value) : generateString(value);
} }
/// Combines [generateType], [generateKey], and [generateValue] to return /// Combines [generateType], [generateKey], and [generateValue] to return
......
...@@ -225,8 +225,8 @@ String genSimpleMethod(Message message) { ...@@ -225,8 +225,8 @@ String genSimpleMethod(Message message) {
for (final Placeholder placeholder in message.placeholders) { for (final Placeholder placeholder in message.placeholders) {
messageValue = messageValue.replaceAll('{${placeholder.name}}', '\${${placeholder.name}}'); messageValue = messageValue.replaceAll('{${placeholder.name}}', '\${${placeholder.name}}');
} }
final String rawMessage = generateString(messageValue); // "r'...'" final String generatedMessage = generateString(messageValue); // "r'...'"
return rawMessage.substring(1); return generatedMessage.startsWith('r') ? generatedMessage.substring(1) : generatedMessage;
} }
List<String> genMethodParameters([String type]) { List<String> genMethodParameters([String type]) {
......
...@@ -371,46 +371,46 @@ String generateClassDeclaration( ...@@ -371,46 +371,46 @@ String generateClassDeclaration(
class $classNamePrefix$camelCaseName extends $superClass {'''; class $classNamePrefix$camelCaseName extends $superClass {''';
} }
/// Return `s` as a Dart-parseable raw string in single or double quotes. /// Return `s` as a Dart-parseable string.
/// ///
/// Double quotes are expanded: /// The result tries to avoid character escaping:
/// ///
/// ``` /// ```
/// foo => r'foo' /// foo => 'foo'
/// foo "bar" => r'foo "bar"' /// foo "bar" => 'foo "bar"'
/// foo 'bar' => r'foo ' "'" r'bar' "'" /// foo 'bar' => "foo 'bar'"
/// foo 'bar' "baz" => '''foo 'bar' "baz"'''
/// foo\bar => r'foo\bar'
/// ``` /// ```
String generateString(String s) { ///
if (!s.contains("'")) /// Strings with newlines are not supported.
return "r'$s'"; String generateString(String value) {
assert(!value.contains('\n'));
final StringBuffer output = StringBuffer(); final String rawPrefix = value.contains(r'$') || value.contains(r'\') ? 'r' : '';
bool started = false; // Have we started writing a raw string. if (!value.contains("'"))
for (int i = 0; i < s.length; i++) { return "$rawPrefix'$value'";
if (s[i] == "'") { if (!value.contains('"'))
if (started) return '$rawPrefix"$value"';
output.write("'"); if (!value.contains("'''"))
output.write(' "\'" '); return "$rawPrefix'''$value'''";
started = false; if (!value.contains('"""'))
} else if (!started) { return '$rawPrefix"""$value"""';
output.write("r'${s[i]}");
started = true; return value.split("'''")
} else { .map(generateString)
output.write(s[i]); // If value contains more than 6 consecutive single quotes some empty strings may be generated.
} // The following map removes them.
} .map((String part) => part == "''" ? '' : part)
if (started) .join(" \"'''\" ");
output.write("'");
return output.toString();
} }
/// Only used to generate localization strings for the Kannada locale ('kn') because /// Only used to generate localization strings for the Kannada locale ('kn') because
/// some of the localized strings contain characters that can crash Emacs on Linux. /// some of the localized strings contain characters that can crash Emacs on Linux.
/// See packages/flutter_localizations/lib/src/l10n/README for more information. /// See packages/flutter_localizations/lib/src/l10n/README for more information.
String generateEncodedString(String s) { String generateEncodedString(String locale, String value) {
if (s.runes.every((int code) => code <= 0xFF)) if (locale != 'kn' || value.runes.every((int code) => code <= 0xFF))
return generateString(s); return generateString(value);
final String unicodeEscapes = s.runes.map((int code) => '\\u{${code.toRadixString(16)}}').join(); final String unicodeEscapes = value.runes.map((int code) => '\\u{${code.toRadixString(16)}}').join();
return "'$unicodeEscapes'"; return "'$unicodeEscapes'";
} }
...@@ -615,7 +615,7 @@ void main() { ...@@ -615,7 +615,7 @@ void main() {
'Title', 'Title',
locale: _localeName, locale: _localeName,
name: 'title', name: 'title',
desc: r'Title for the application' desc: 'Title for the application'
); );
} }
'''); ''');
...@@ -657,10 +657,10 @@ void main() { ...@@ -657,10 +657,10 @@ void main() {
generator.classMethods.first, generator.classMethods.first,
''' String itemNumber(Object value) { ''' String itemNumber(Object value) {
return Intl.message( return Intl.message(
\'Item \${value}\', 'Item \${value}',
locale: _localeName, locale: _localeName,
name: 'itemNumber', name: 'itemNumber',
desc: r\'Item placement in list.\', desc: 'Item placement in list.',
args: <Object>[value] args: <Object>[value]
); );
} }
...@@ -710,10 +710,10 @@ void main() { ...@@ -710,10 +710,10 @@ void main() {
String springBegins(Object springStartDate) { String springBegins(Object springStartDate) {
return Intl.message( return Intl.message(
\'Spring begins on \${springStartDate}\', 'Spring begins on \${springStartDate}',
locale: _localeName, locale: _localeName,
name: \'springBegins\', name: 'springBegins',
desc: r\'The first day of spring\', desc: 'The first day of spring',
args: <Object>[springStartDate] args: <Object>[springStartDate]
); );
} }
...@@ -837,10 +837,10 @@ void main() { ...@@ -837,10 +837,10 @@ void main() {
String springGreetings(Object springStartDate, Object helloWorld) { String springGreetings(Object springStartDate, Object helloWorld) {
return Intl.message( return Intl.message(
\'Since it\' "\'" r\'s \${springStartDate}, it\' "\'" r\'s finally spring! \${helloWorld}!\', "Since it's \${springStartDate}, it's finally spring! \${helloWorld}!",
locale: _localeName, locale: _localeName,
name: \'springGreetings\', name: 'springGreetings',
desc: r\'A realization that it\' "\'" r\'s finally the spring season, followed by a greeting.\', desc: "A realization that it's finally the spring season, followed by a greeting.",
args: <Object>[springStartDate, helloWorld] args: <Object>[springStartDate, helloWorld]
); );
} }
...@@ -897,10 +897,10 @@ void main() { ...@@ -897,10 +897,10 @@ void main() {
String springRange(Object springStartDate, Object springEndDate) { String springRange(Object springStartDate, Object springEndDate) {
return Intl.message( return Intl.message(
\'Spring begins on \${springStartDate} and ends on \${springEndDate}\', 'Spring begins on \${springStartDate} and ends on \${springEndDate}',
locale: _localeName, locale: _localeName,
name: \'springRange\', name: 'springRange',
desc: r\'The range of dates for spring in the year\', desc: 'The range of dates for spring in the year',
args: <Object>[springStartDate, springEndDate] args: <Object>[springStartDate, springEndDate]
); );
} }
...@@ -1009,10 +1009,10 @@ void main() { ...@@ -1009,10 +1009,10 @@ void main() {
String courseCompletion(Object progress) { String courseCompletion(Object progress) {
return Intl.message( return Intl.message(
\'You have completed \${progress} of the course.\', 'You have completed \${progress} of the course.',
locale: _localeName, locale: _localeName,
name: \'courseCompletion\', name: 'courseCompletion',
desc: r\'The amount of progress the student has made in their class.\', desc: 'The amount of progress the student has made in their class.',
args: <Object>[progress] args: <Object>[progress]
); );
} }
...@@ -1079,10 +1079,10 @@ void main() { ...@@ -1079,10 +1079,10 @@ void main() {
String courseCompletion(Object progress) { String courseCompletion(Object progress) {
return Intl.message( return Intl.message(
\'You have completed \${progress} of the course.\', 'You have completed \${progress} of the course.',
locale: _localeName, locale: _localeName,
name: \'courseCompletion\', name: 'courseCompletion',
desc: r\'The amount of progress the student has made in their class.\', desc: 'The amount of progress the student has made in their class.',
args: <Object>[progress] args: <Object>[progress]
); );
} }
...@@ -1139,10 +1139,10 @@ void main() { ...@@ -1139,10 +1139,10 @@ void main() {
String courseCompletion(Object progress) { String courseCompletion(Object progress) {
return Intl.message( return Intl.message(
\'You have completed \${progress} of the course.\', 'You have completed \${progress} of the course.',
locale: _localeName, locale: _localeName,
name: \'courseCompletion\', name: 'courseCompletion',
desc: r\'The amount of progress the student has made in their class.\', desc: 'The amount of progress the student has made in their class.',
args: <Object>[progress] args: <Object>[progress]
); );
} }
...@@ -1706,4 +1706,37 @@ void main() { ...@@ -1706,4 +1706,37 @@ void main() {
expect(outputFileString, contains('class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations>')); expect(outputFileString, contains('class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations>'));
}); });
}); });
group('generateString', () {
test('handles simple string', () {
expect(generateString('abc'), "'abc'");
});
test('handles string with quote', () {
expect(generateString("ab'c"), '''"ab'c"''');
});
test('handles string with double quote', () {
expect(generateString('ab"c'), """'ab"c'""");
});
test('handles string with both single and double quote', () {
expect(generateString('''a'b"c'''), """'''a'b"c'''""");
});
test('handles string with a triple single quote and a double quote', () {
expect(generateString("""a"b'''c"""), '''"""a"b\'''c"""''');
});
test('handles string with a triple double quote and a single quote', () {
expect(generateString('''a'b"""c'''), """'''a'b\"""c'''""");
});
test('handles string with both triple single and triple double quote', () {
expect(generateString('''a\'''\'''\''b"""c'''), """'a' "'''" "'''" '''''b\"""c'''""");
});
test('handles dollar', () {
expect(generateString(r'ab$c'), r"r'ab$c'");
});
test('handles back slash', () {
expect(generateString(r'ab\c'), r"r'ab\c'");
});
test("doesn't support multiline strings", () {
expect(() => generateString('ab\nc'), throwsA(isA<AssertionError>()));
});
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment