refactor: enforce lint rules
This commit is contained in:
parent
e4bb807a30
commit
829ced74d6
29
README.md
29
README.md
|
@ -27,41 +27,39 @@ Container(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Be default, The above snippet would linkify all urls in the string, you can choose what type of link to linkify by passing the `linkTypes` parameter
|
Be default, The above snippet would linkify all urls in the string, you can choose what type of link to linkify by passing the `Links` parameter
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
Container(
|
Container(
|
||||||
child: LinkifyText(
|
child: LinkifyText(
|
||||||
"This text contains a url: https://flutter.dev and #flutter",
|
"This text contains a url: https://flutter.dev and #flutter",
|
||||||
linkStyle: TextStyle(color: Colors.blue, fontSize: 16),
|
linkStyle: TextStyle(color: Colors.blue, fontSize: 16),
|
||||||
linkTypes: [LinkType.url, LinkType.hashtag]
|
Links: [Link.url, Link.hashtag]
|
||||||
onTap: (link) {
|
onTap: (link) {
|
||||||
/// do stuff with `link` like
|
/// do stuff with `link` like
|
||||||
/// if(link.type == Linktype.url) launchUrl(link.value);
|
/// if(link.type == Link.url) launchUrl(link.value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
#### LinkfyText
|
#### LinkfyText
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| :-------- | :------- | :-------------------------------- |
|
| :---------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `textStyle` | `TextStyle` | style applied to the text |
|
| `textStyle` | `TextStyle` | style applied to the text |
|
||||||
| `linkStyle` | `TextStyle` | style applied to the linkified text. **defaults** to `textStyle` |
|
| `linkStyle` | `TextStyle` | style applied to the linkified text. **defaults** to `textStyle` |
|
||||||
| `linkTypes` | `List<LinkType>` | a list of `LinkType` used to override the links to be linkified in a text either a url, hashtag or email. **defaults** to `[LinkType.url]`|
|
| `Links` | `List<Link>` | a list of `Link` used to override the links to be linkified in a text either a url, hashtag or email. **defaults** to `[Link.url]` |
|
||||||
| `onTap` | `Function(Link)` | function called when a link is pressed |
|
| `onTap` | `Function(Link)` | function called when a link is pressed |
|
||||||
|
|
||||||
|
|
||||||
#### Link
|
#### Link
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| :-------- | :------- | :-------------------------------- |
|
| :-------- | :------- | :----------------------------------------- |
|
||||||
| `type` | `LinkType` | the link type either url, email or hashtag |
|
| `type` | `Link` | the link type either url, email or hashtag |
|
||||||
| `value` | `String` | value this link holds |
|
| `value` | `String` | value this link holds |
|
||||||
|
|
||||||
# Contributions
|
# Contributions
|
||||||
|
|
||||||
|
@ -72,5 +70,4 @@ If you fixed a bug or implemented a feature, please send a [pull request](https:
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
- linkify "@" mention and "$" sign
|
|
||||||
- LinkifyTextField widget
|
- LinkifyTextField widget
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
include: package:lint/analysis_options.yaml
|
||||||
|
analyzer:
|
||||||
|
errors:
|
||||||
|
missing_required_param: error
|
||||||
|
todo: info
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
always-specify-types: true
|
||||||
|
prefer-relative-imports: true
|
||||||
|
sort_pub_dependencies: false
|
||||||
|
unnecessary_raw_strings: false
|
|
@ -12,7 +12,7 @@ class MyApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'linkify_text Demo',
|
title: 'linkfy_text Demo',
|
||||||
scaffoldMessengerKey: _msgKey,
|
scaffoldMessengerKey: _msgKey,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: App(),
|
home: App(),
|
||||||
|
|
|
@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
@ -27,7 +27,6 @@ dependencies:
|
||||||
linkfy_text:
|
linkfy_text:
|
||||||
path: ../
|
path: ../
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/// A lightweight flutter package to linkify texts containing urls, emails and hashtags.
|
/// A lightweight flutter package to linkify texts containing urls, emails and hashtags.
|
||||||
library linkfy_text;
|
library linkfy_text;
|
||||||
|
|
||||||
export 'src/linkify.dart';
|
|
||||||
export 'src/enum.dart';
|
export 'src/enum.dart';
|
||||||
|
export 'src/linkify.dart';
|
||||||
|
|
|
@ -157,22 +157,22 @@ TextSpan _linkify({
|
||||||
List<LinkType>? linkTypes,
|
List<LinkType>? linkTypes,
|
||||||
Function(Link)? onTap,
|
Function(Link)? onTap,
|
||||||
}) {
|
}) {
|
||||||
RegExp _regExp = constructRegExpFromLinkType(linkTypes ?? [LinkType.url]);
|
final _regExp = constructRegExpFromLinkType(linkTypes ?? [LinkType.url]);
|
||||||
|
|
||||||
// return the full text if there's no match or if empty
|
// return the full text if there's no match or if empty
|
||||||
if (!_regExp.hasMatch(text) || text.isEmpty) return TextSpan(text: text);
|
if (!_regExp.hasMatch(text) || text.isEmpty) return TextSpan(text: text);
|
||||||
|
|
||||||
List<String> texts = text.split(_regExp);
|
final texts = text.split(_regExp);
|
||||||
List<TextSpan> spans = [];
|
final List<InlineSpan> spans = [];
|
||||||
List<RegExpMatch> links = _regExp.allMatches(text).toList();
|
final links = _regExp.allMatches(text).toList();
|
||||||
|
|
||||||
for (String text in texts) {
|
for (final text in texts) {
|
||||||
spans.add(TextSpan(
|
spans.add(TextSpan(
|
||||||
text: text,
|
text: text,
|
||||||
));
|
));
|
||||||
if (links.length > 0) {
|
if (links.isNotEmpty) {
|
||||||
RegExpMatch match = links.removeAt(0);
|
final match = links.removeAt(0);
|
||||||
Link link = Link.fromMatch(match);
|
final link = Link.fromMatch(match);
|
||||||
// add the link
|
// add the link
|
||||||
spans.add(
|
spans.add(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
|
|
|
@ -2,13 +2,13 @@ import 'package:linkfy_text/src/enum.dart';
|
||||||
import 'package:linkfy_text/src/utils/regex.dart';
|
import 'package:linkfy_text/src/utils/regex.dart';
|
||||||
|
|
||||||
class Link {
|
class Link {
|
||||||
String? _value;
|
final String? _value;
|
||||||
LinkType? _type;
|
final LinkType? _type;
|
||||||
String? get value => _value;
|
String? get value => _value;
|
||||||
LinkType? get type => _type;
|
LinkType? get type => _type;
|
||||||
|
|
||||||
/// construct link from matched regExp
|
/// construct link from matched regExp
|
||||||
Link.fromMatch(RegExpMatch match)
|
Link.fromMatch(RegExpMatch match)
|
||||||
: this._type = getMatchedType(match),
|
: _type = getMatchedType(match),
|
||||||
this._value = match.input.substring(match.start, match.end);
|
_value = match.input.substring(match.start, match.end);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,46 +6,55 @@ String hashtagRegExp = r'(#+[a-zA-Z0-9(_)]{1,})';
|
||||||
|
|
||||||
String userTagRegExp = r'(?<![\w@])@([\w@]+(?:[.!][\w@]+)*)';
|
String userTagRegExp = r'(?<![\w@])@([\w@]+(?:[.!][\w@]+)*)';
|
||||||
|
|
||||||
String emailRegExp = r"([a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+)";
|
String emailRegExp =
|
||||||
|
r"([a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+)";
|
||||||
|
|
||||||
/// construct regexp. pattern from provided link linkTypes
|
/// construct regexp. pattern from provided link types
|
||||||
RegExp constructRegExpFromLinkType(List<LinkType> linkTypes) {
|
RegExp constructRegExpFromLinkType(List<LinkType> types) {
|
||||||
// default case where we always want to match url strings
|
// default case where we always want to match url strings
|
||||||
if (linkTypes.length == 1 && linkTypes.first == LinkType.url) return RegExp(urlRegExp);
|
final len = types.length;
|
||||||
|
if (len == 1 && types.first == LinkType.url) {
|
||||||
StringBuffer _regexBuffer = StringBuffer();
|
return RegExp(urlRegExp);
|
||||||
for (var i = 0; i < linkTypes.length; i++) {
|
}
|
||||||
final _type = linkTypes[i];
|
final buffer = StringBuffer();
|
||||||
final _isLast = i == linkTypes.length - 1;
|
for (var i = 0; i < len; i++) {
|
||||||
switch (_type) {
|
final type = types[i];
|
||||||
|
final isLast = i == len - 1;
|
||||||
|
switch (type) {
|
||||||
case LinkType.url:
|
case LinkType.url:
|
||||||
_isLast ? _regexBuffer.write("($urlRegExp)") : _regexBuffer.write("($urlRegExp)|");
|
isLast ? buffer.write("($urlRegExp)") : buffer.write("($urlRegExp)|");
|
||||||
break;
|
break;
|
||||||
case LinkType.hashTag:
|
case LinkType.hashTag:
|
||||||
_isLast ? _regexBuffer.write("($hashtagRegExp)") : _regexBuffer.write("($hashtagRegExp)|");
|
isLast
|
||||||
|
? buffer.write("($hashtagRegExp)")
|
||||||
|
: buffer.write("($hashtagRegExp)|");
|
||||||
break;
|
break;
|
||||||
case LinkType.userTag:
|
case LinkType.userTag:
|
||||||
_isLast ? _regexBuffer.write("($userTagRegExp)") : _regexBuffer.write("($userTagRegExp)|");
|
isLast
|
||||||
|
? buffer.write("($userTagRegExp)")
|
||||||
|
: buffer.write("($userTagRegExp)|");
|
||||||
break;
|
break;
|
||||||
case LinkType.email:
|
case LinkType.email:
|
||||||
_isLast ? _regexBuffer.write("($emailRegExp)") : _regexBuffer.write("($emailRegExp)|");
|
isLast
|
||||||
|
? buffer.write("($emailRegExp)")
|
||||||
|
: buffer.write("($emailRegExp)|");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RegExp(_regexBuffer.toString());
|
return RegExp(buffer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkType getMatchedType(RegExpMatch match) {
|
LinkType getMatchedType(RegExpMatch match) {
|
||||||
late LinkType _type;
|
late LinkType type;
|
||||||
if (RegExp(urlRegExp).hasMatch(match.input)) {
|
if (RegExp(urlRegExp).hasMatch(match.input)) {
|
||||||
_type = LinkType.url;
|
type = LinkType.url;
|
||||||
} else if (RegExp(hashtagRegExp).hasMatch(match.input)) {
|
} else if (RegExp(hashtagRegExp).hasMatch(match.input)) {
|
||||||
_type = LinkType.hashTag;
|
type = LinkType.hashTag;
|
||||||
} else if (RegExp(emailRegExp).hasMatch(match.input)) {
|
} else if (RegExp(emailRegExp).hasMatch(match.input)) {
|
||||||
_type = LinkType.email;
|
type = LinkType.email;
|
||||||
} else if (RegExp(userTagRegExp).hasMatch(match.input)) {
|
} else if (RegExp(userTagRegExp).hasMatch(match.input)) {
|
||||||
_type = LinkType.userTag;
|
type = LinkType.userTag;
|
||||||
}
|
}
|
||||||
return _type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,6 +151,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.3"
|
version: "0.6.3"
|
||||||
|
lint:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: lint
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.3"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -15,6 +15,7 @@ dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
test: ^1.16.5
|
test: ^1.16.5
|
||||||
|
lint: ^1.5.3
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
|
@ -4,17 +4,17 @@ import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('Regular Expression', () {
|
group('Regular Expression', () {
|
||||||
/// test values
|
// test values
|
||||||
final _urlText =
|
const urlText =
|
||||||
"My website url: https://hello.com/GOOGLE search using: www.google.com, social media is facebook.com, http://example.com/method?param=fullstackoverflow.dev";
|
"My website url: https://hello.com/GOOGLE search using: www.google.com, social media is facebook.com, http://example.com/method?param=fullstackoverflow.dev";
|
||||||
final _hashtagText = "#helloWorld and #dev are trending";
|
const hashtagText = "#helloWorld and #dev are trending";
|
||||||
final _emailText =
|
const emailText =
|
||||||
"My email address is hey@stanleee.me and dev@gmail.com, yah!";
|
"My email address is hey@stanleee.me and dev@gmail.com, yah!";
|
||||||
final _text = _urlText + _hashtagText + _emailText;
|
const text = urlText + hashtagText + emailText;
|
||||||
|
|
||||||
final _emails = ["hello@world.com", "foo.bar@js.com"];
|
const emails = ["hello@world.com", "foo.bar@js.com"];
|
||||||
|
|
||||||
final List<String> _urls = [
|
const urls = [
|
||||||
"http://domain.com",
|
"http://domain.com",
|
||||||
"http://domain.com/",
|
"http://domain.com/",
|
||||||
"https://domain.com",
|
"https://domain.com",
|
||||||
|
@ -28,7 +28,7 @@ void main() {
|
||||||
"https://sub.domain.com/Google?param=helloworld#hash",
|
"https://sub.domain.com/Google?param=helloworld#hash",
|
||||||
];
|
];
|
||||||
|
|
||||||
final List<String> _hashtags = [
|
const hashtags = [
|
||||||
"#123",
|
"#123",
|
||||||
"#H",
|
"#H",
|
||||||
"#0",
|
"#0",
|
||||||
|
@ -38,46 +38,51 @@ void main() {
|
||||||
"#trending_topic",
|
"#trending_topic",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const userTags = [
|
||||||
|
'@helloWorld',
|
||||||
|
'@helloWorld123',
|
||||||
|
'@hello_world',
|
||||||
|
'@hello_world123',
|
||||||
|
'@hello_world_123'
|
||||||
|
];
|
||||||
|
|
||||||
///
|
///
|
||||||
test("Should match all emails", () {
|
test("Should match all emails", () {
|
||||||
_emails.forEach((e) {
|
for (final email in emails) {
|
||||||
bool hasMatch = RegExp(emailRegExp).hasMatch(e);
|
expect(RegExp(emailRegExp).hasMatch(email), isTrue);
|
||||||
expect(hasMatch, isTrue);
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Should not match all emails", () {
|
|
||||||
List<String> _emails = ["hello@world", "@js.com"];
|
|
||||||
_emails.forEach((e) {
|
|
||||||
bool hasMatch = RegExp(emailRegExp).hasMatch(e);
|
|
||||||
expect(hasMatch, isFalse);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Should match all urls", () {
|
test("Should match all urls", () {
|
||||||
_urls.forEach((u) {
|
for (final url in urls) {
|
||||||
bool hasMatch = RegExp(urlRegExp).hasMatch(u);
|
expect(RegExp(urlRegExp).hasMatch(url), isTrue);
|
||||||
expect(hasMatch, isTrue);
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Should match all hashtags", () {
|
test("Should match all hashtags", () {
|
||||||
_hashtags.forEach((h) {
|
for (final tag in hashtags) {
|
||||||
bool hasMatch = RegExp(hashtagRegExp).hasMatch(h);
|
expect(RegExp(hashtagRegExp).hasMatch(tag), isTrue);
|
||||||
expect(hasMatch, isTrue);
|
}
|
||||||
});
|
});
|
||||||
|
test("Should match all usertags", () {
|
||||||
|
for (final tag in userTags) {
|
||||||
|
expect(RegExp(userTagRegExp).hasMatch(tag), isTrue);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Should construct regex pattern from LinkTypes and match length", () {
|
test(
|
||||||
RegExp _urlRegExp = constructRegExpFromLinkType([LinkType.url]);
|
"Should construct regex pattern from LinkTypes and match required output",
|
||||||
RegExp _hashtagRegExp = constructRegExpFromLinkType([LinkType.hashTag]);
|
() {
|
||||||
RegExp _emailRegExp = constructRegExpFromLinkType([LinkType.email]);
|
final urlRegExp = constructRegExpFromLinkType([LinkType.url]);
|
||||||
RegExp _textRegExp = constructRegExpFromLinkType(
|
final hashtagRegExp = constructRegExpFromLinkType([LinkType.hashTag]);
|
||||||
|
final emailRegExp = constructRegExpFromLinkType([LinkType.email]);
|
||||||
|
final textRegExp = constructRegExpFromLinkType(
|
||||||
[LinkType.url, LinkType.hashTag, LinkType.email]);
|
[LinkType.url, LinkType.hashTag, LinkType.email]);
|
||||||
expect(_urlRegExp.allMatches(_urlText).length, 4);
|
|
||||||
expect(_hashtagRegExp.allMatches(_hashtagText).length, 2);
|
expect(urlRegExp.allMatches(urlText).length, 4);
|
||||||
expect(_emailRegExp.allMatches(_emailText).length, 2);
|
expect(hashtagRegExp.allMatches(hashtagText).length, 2);
|
||||||
expect(_textRegExp.allMatches(_text).length, 8);
|
expect(emailRegExp.allMatches(emailText).length, 2);
|
||||||
|
expect(textRegExp.allMatches(text).length, 8);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue