Skip to content

Commit 4826e14

Browse files
authored
fix(mason_logger): link should depend on ansi escape support (#1505)
1 parent 4de5083 commit 4826e14

File tree

9 files changed

+94
-37
lines changed

9 files changed

+94
-37
lines changed

.github/workflows/mason.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,4 @@ jobs:
9090
dart pub global activate pana
9191
9292
- name: Verify Pub Score
93-
run: ../../tool/verify_pub_score.sh
93+
run: ../../tool/verify_pub_score.sh 150

packages/mason/lib/src/brick_yaml.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,21 +100,21 @@ class BrickYaml {
100100

101101
/// The type of brick variable.
102102
enum BrickVariableType {
103-
/// An array (e.g. ["one", "two", "three"]).
103+
/// An array (e.g. `["one", "two", "three"]`).
104104
/// Values must be present in the list of
105105
/// available options.
106106
array,
107107

108-
/// A number (e.g. 42)
108+
/// A number (e.g. `42`)
109109
number,
110110

111-
/// A string (e.g. "Dash")
111+
/// A string (e.g. `"Dash"`)
112112
string,
113113

114-
/// A boolean (e.g. true/false)
114+
/// A boolean (e.g. `true`/`false`)
115115
boolean,
116116

117-
/// An enumeration (e.g. ["red", "green", "blue"])
117+
/// An enumeration (e.g. `["red", "green", "blue"]`)
118118
@JsonValue('enum')
119119
enumeration,
120120

packages/mason/lib/src/mason_lock_json.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ part 'mason_lock_json.g.dart';
88
/// {@endtemplate}
99
@JsonSerializable()
1010
class MasonLockJson {
11-
/// {@macro mason_lock}
11+
/// {@macro mason_lock_json}
1212
const MasonLockJson({Map<String, BrickLocation>? bricks})
1313
: bricks = bricks ?? const <String, BrickLocation>{};
1414

packages/mason/test/src/bundler_test.dart

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void main() {
6767

6868
expect(bundle.name, equals('hello'));
6969
expect(bundle.description, equals('An example brick.'));
70-
expect(bundle.version, equals('0.1.0+1'));
70+
expect(bundle.version, equals('0.1.0+2'));
7171
expect(
7272
bundle.repository,
7373
equals('https://github.com/felangel/mason/tree/master/bricks/hello'),
@@ -238,7 +238,7 @@ void main() {
238238
equals(
239239
'name: hello\n'
240240
'description: An example brick.\n'
241-
'version: 0.1.0+1\n'
241+
'version: 0.1.0+2\n'
242242
'environment:\n'
243243
' mason: ^$packageVersion\n'
244244
'repository: "https://github.com/felangel/mason/tree/master/bricks/hello"\n'
@@ -259,45 +259,57 @@ void main() {
259259
expect(readme.existsSync(), isTrue);
260260
expect(
261261
readme.readAsNormalizedStringSync(),
262-
equals(
263-
'# hello\n'
264-
'\n'
265-
'A new brick created with the Mason CLI.\n'
266-
'\n'
267-
'_Generated by [mason][1] 🧱_\n'
268-
'\n'
269-
'## Getting Started 🚀\n'
270-
'\n'
271-
'This is a starting point for a new brick.\n'
272-
'''A few resources to get you started if this is your first brick template:\n'''
273-
'\n'
274-
'- [Official Mason Documentation][2]\n'
275-
'- [Code generation with Mason Blog][3]\n'
276-
'- [Very Good Livestream: Felix Angelov Demos Mason][4]\n'
277-
'\n'
278-
'[1]: https://github.com/felangel/mason\n'
279-
'[2]: https://github.com/felangel/mason/tree/master/packages/mason_cli#readme\n'
280-
'[3]: https://verygood.ventures/blog/code-generation-with-mason\n'
281-
'[4]: https://youtu.be/G4PTjA6tpTU\n',
282-
),
262+
equals('# hello\n'
263+
'\n'
264+
'A hello world brick created with the Mason CLI.\n'
265+
'\n'
266+
'_Generated by [mason][1] 🧱_\n'
267+
'\n'
268+
'[1]: https://github.com/felangel/mason\n'),
283269
);
284270

285271
final changelog = File(path.join(tempDir.path, 'CHANGELOG.md'));
286272
expect(changelog.existsSync(), isTrue);
287273
expect(
288274
changelog.readAsNormalizedStringSync(),
289275
equals(
276+
'# 0.1.0+2\n'
277+
'\n'
278+
'- chore: upgrade to `mason ^0.1.0`\n'
279+
'\n'
290280
'# 0.1.0+1\n'
291281
'\n'
292-
'- TODO: Describe initial release.\n',
282+
'- chore: initial release\n',
293283
),
294284
);
295285

296286
final license = File(path.join(tempDir.path, 'LICENSE'));
297287
expect(license.existsSync(), isTrue);
298288
expect(
299289
license.readAsNormalizedStringSync(),
300-
equals('TODO: Add your license here.\n'),
290+
equals(
291+
'The MIT License (MIT)\n'
292+
'Copyright (c) 2024 Felix Angelov\n'
293+
'\n'
294+
'Permission is hereby granted, free of charge, to any person\n'
295+
'obtaining a copy of this software and associated documentation\n'
296+
'''files (the "Software"), to deal in the Software without restriction,\n'''
297+
'''including without limitation the rights to use, copy, modify, merge,\n'''
298+
'''publish, distribute, sublicense, and/or sell copies of the Software,\n'''
299+
'''and to permit persons to whom the Software is furnished to do so,\n'''
300+
'subject to the following conditions:\n'
301+
'\n'
302+
'''The above copyright notice and this permission notice shall be included\n'''
303+
'in all copies or substantial portions of the Software.\n'
304+
'\n'
305+
'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\n'
306+
'''EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n'''
307+
'''MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n'''
308+
'''IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n'''
309+
'''DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n'''
310+
'''OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n'''
311+
'USE OR OTHER DEALINGS IN THE SOFTWARE.',
312+
),
301313
);
302314
});
303315

packages/mason_cli/test/commands/make_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ bricks:
452452

453453
test('exits with code 70 when exception occurs while generating', () async {
454454
const url =
455-
'https://cdn.dribbble.com/users/163325/screenshots/6214023/app_icon.jpg';
455+
'https://storage.googleapis.com/cms-storage-bucket/c823e53b3a1a7b0d36a9.png';
456456
when(
457457
() => logger.prompt(any(), defaultValue: any(named: 'defaultValue')),
458458
).thenReturn(url);
@@ -485,7 +485,7 @@ bricks:
485485
'make',
486486
'app_icon',
487487
'--url',
488-
'https://cdn.dribbble.com/users/163325/screenshots/6214023/app_icon.jpg',
488+
'https://storage.googleapis.com/cms-storage-bucket/c823e53b3a1a7b0d36a9.png',
489489
]);
490490
expect(result, equals(ExitCode.success.code));
491491

@@ -500,7 +500,7 @@ bricks:
500500

501501
test('generates app_icon (from prompt)', () async {
502502
const url =
503-
'https://cdn.dribbble.com/users/163325/screenshots/6214023/app_icon.jpg';
503+
'https://storage.googleapis.com/cms-storage-bucket/c823e53b3a1a7b0d36a9.png';
504504
when(() => logger.prompt(any())).thenReturn(url);
505505
final testDir = Directory(
506506
path.join(Directory.current.path, 'app_icon'),
-409 KB
Binary file not shown.
7.06 KB
Loading

packages/mason_logger/lib/src/link.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'package:io/ansi.dart';
2+
13
/// Wraps [uri] with an escape sequence so it's recognized as a hyperlink.
24
/// An optional message can be used in place of the [uri].
35
/// If no [message] is provided, the text content will be the full [uri].
@@ -10,6 +12,10 @@
1012
/// print(richLink); // Equivalent to `[The Dart Website](https://dart.dev)` in markdown
1113
/// ```
1214
String link({required Uri uri, String? message}) {
15+
if (!ansiOutputEnabled) {
16+
return message != null ? '[$message]($uri)' : uri.toString();
17+
}
18+
1319
const leading = '\x1B]8;;';
1420
const trailing = '\x1B\\';
1521

packages/mason_logger/test/src/link_test.dart

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
1+
import 'dart:io';
2+
13
import 'package:mason_logger/mason_logger.dart';
4+
import 'package:mocktail/mocktail.dart';
25
import 'package:test/test.dart';
36

7+
class _MockStdout extends Mock implements Stdout {}
8+
49
void main() {
510
group('link', () {
11+
late Stdout stdout;
12+
late Stdout stderr;
13+
14+
setUp(() {
15+
stdout = _MockStdout();
16+
stderr = _MockStdout();
17+
when(() => stdout.supportsAnsiEscapes).thenReturn(true);
18+
when(() => stderr.supportsAnsiEscapes).thenReturn(true);
19+
});
20+
21+
R runWithOverrides<R>(R Function() body) {
22+
return IOOverrides.runZoned(
23+
body,
24+
stdout: () => stdout,
25+
stderr: () => stderr,
26+
);
27+
}
28+
629
final uri = Uri.parse('https://github.com/felangel/mason/issues/');
730
const lead = '\x1B]8;;';
831
const trail = '\x1B\\';
@@ -11,7 +34,7 @@ void main() {
1134
'builds output with correct encodings: ' r'\x1B]8;;' ' and ' r'\x1B\\',
1235
() {
1336
const message = 'message';
14-
final output = link(message: message, uri: uri);
37+
final output = runWithOverrides(() => link(message: message, uri: uri));
1538
final matcher = stringContainsInOrder(
1639
[lead, '$uri', trail, message, lead, trail],
1740
);
@@ -21,12 +44,28 @@ void main() {
2144
);
2245

2346
test('builds String with Uri when message is null: ', () {
24-
final output = link(uri: uri);
47+
final output = runWithOverrides(() => link(uri: uri));
2548
final matcher = stringContainsInOrder(
2649
[lead, '$uri', trail, '$uri', lead, trail],
2750
);
2851

2952
expect(output, matcher);
3053
});
54+
55+
test('builds output when ansi escapes are not supported', () {
56+
when(() => stdout.supportsAnsiEscapes).thenReturn(false);
57+
when(() => stderr.supportsAnsiEscapes).thenReturn(false);
58+
final output = runWithOverrides(() => link(uri: uri));
59+
final matcher = stringContainsInOrder(['$uri']);
60+
expect(output, matcher);
61+
});
62+
63+
test('builds output with message when ansi escapes are not supported', () {
64+
when(() => stdout.supportsAnsiEscapes).thenReturn(false);
65+
when(() => stderr.supportsAnsiEscapes).thenReturn(false);
66+
const message = 'message';
67+
final output = runWithOverrides(() => link(uri: uri, message: message));
68+
expect(output, equals('[$message]($uri)'));
69+
});
3170
});
3271
}

0 commit comments

Comments
 (0)