| // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import "package:expect/expect.dart"; | |
| import 'package:compiler/src/constants/values.dart' show StringConstantValue; | |
| import 'package:compiler/src/js_backend/string_reference.dart' | |
| show StringReference, StringReferenceResource, StringReferenceFinalizerImpl; | |
| import 'package:compiler/src/js/js.dart' show prettyPrint; | |
| import 'package:js_ast/js_ast.dart' as js; | |
| void test(List<String> strings, String expected, {bool minified = false}) { | |
| var finalizer = StringReferenceFinalizerImpl( | |
| minified, | |
| shortestSharedLength: 5, | |
| ); | |
| for (var string in strings) { | |
| finalizer.addCode(StringReference(StringConstantValue(string))); | |
| } | |
| StringReferenceResource resource = StringReferenceResource(); | |
| finalizer.registerStringReferenceResource(resource); | |
| finalizer.finalize(); | |
| // Wrap the resource in a block, as they would print in actual code. | |
| Expect.equals(expected.trim(), prettyPrint(js.Block([resource])).trim()); | |
| } | |
| extension on List<String> { | |
| List<String> operator *(int count) { | |
| return List.filled(count, this).expand((list) => list).toList(); | |
| } | |
| } | |
| void main() { | |
| // No strings yields an empty pool. | |
| test([], r''' | |
| { | |
| }'''); | |
| // Single occurrence strings are not pooled. | |
| test( | |
| ['Yellow', 'Blue', 'Crimson'], | |
| r''' | |
| { | |
| }''', | |
| ); | |
| // Repeated strings that are long enough are pooled. | |
| test( | |
| ['Yellow', 'Blue', 'Blue', 'Crimson', 'Crimson'], | |
| r''' | |
| { | |
| var string$ = { | |
| Crimso: "Crimson" | |
| }; | |
| }''', | |
| ); | |
| // Readable property names have identical stretches compressed-out. | |
| var greets = [ | |
| 'Greetings Bob Smith', | |
| 'Great work!', | |
| 'Greetings Alice', | |
| 'Greetings Bob Henry', | |
| ]; | |
| test(greets * 2, r''' | |
| { | |
| var string$ = { | |
| Great_: "Great work!", | |
| GreetiA: "Greetings Alice", | |
| GreetiBH: "Greetings Bob Henry", | |
| GreetiBS: "Greetings Bob Smith" | |
| }; | |
| }'''); | |
| // Non-identifiers are replaced with '_' if that is unambiguous. | |
| test(['xylograph', '!pingpong'] * 2, r''' | |
| { | |
| var string$ = { | |
| _pingp: "!pingpong", | |
| xylogr: "xylograph" | |
| }; | |
| }'''); | |
| final strings1 = [ | |
| ...['a xylograph'] * 2, | |
| ...['a !pingpong'] * 4, | |
| ...['a %percent'] * 6, | |
| ]; | |
| // Multiple discriminating non-identifier characters are replaced with an | |
| // escape, which causes a potentially ambiguous non-escape to be escaped. | |
| test(strings1, r''' | |
| { | |
| var string$ = { | |
| a_x21pin: "a !pingpong", | |
| a_x25per: "a %percent", | |
| a_x78ylo: "a xylograph" | |
| }; | |
| }'''); | |
| // Minified version keeps the strings in the same order as unminified, and | |
| // tries to allocate the same minified name. | |
| const minified1 = r''' | |
| { | |
| var string$ = { | |
| l: "a !pingpong", | |
| o: "a %percent", | |
| n: "a xylograph" | |
| }; | |
| }'''; | |
| final strings2 = [ | |
| ...['a xylograph'] * 20, // now most frequent. | |
| ...strings1, | |
| ]; | |
| test(strings1, minified1, minified: true); | |
| test(strings2, minified1, minified: true); | |
| } |