refactor: enforce lint rules

This commit is contained in:
iamstanlee 2021-09-02 18:24:27 -07:00
parent e4bb807a30
commit 829ced74d6
11 changed files with 120 additions and 91 deletions

View File

@ -27,40 +27,38 @@ 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
Container(
child: LinkifyText(
"This text contains a url: https://flutter.dev and #flutter",
linkStyle: TextStyle(color: Colors.blue, fontSize: 16),
linkTypes: [LinkType.url, LinkType.hashtag]
Links: [Link.url, Link.hashtag]
onTap: (link) {
/// do stuff with `link` like
/// if(link.type == Linktype.url) launchUrl(link.value);
/// if(link.type == Link.url) launchUrl(link.value);
},
);
)
```
## API Reference
#### LinkfyText
| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| :---------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
| `textStyle` | `TextStyle` | style applied to the text |
| `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 |
#### Link
| 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 |
# Contributions
@ -72,5 +70,4 @@ If you fixed a bug or implemented a feature, please send a [pull request](https:
# TODO
- linkify "@" mention and "$" sign
- LinkifyTextField widget

11
analysis_options.yaml Normal file
View File

@ -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

View File

@ -12,7 +12,7 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'linkify_text Demo',
title: 'linkfy_text Demo',
scaffoldMessengerKey: _msgKey,
debugShowCheckedModeBanner: false,
home: App(),

View File

@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: '>=2.12.0 <3.0.0'
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
@ -27,7 +27,6 @@ dependencies:
linkfy_text:
path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2

View File

@ -1,5 +1,5 @@
/// A lightweight flutter package to linkify texts containing urls, emails and hashtags.
library linkfy_text;
export 'src/linkify.dart';
export 'src/enum.dart';
export 'src/linkify.dart';

View File

@ -157,22 +157,22 @@ TextSpan _linkify({
List<LinkType>? linkTypes,
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
if (!_regExp.hasMatch(text) || text.isEmpty) return TextSpan(text: text);
List<String> texts = text.split(_regExp);
List<TextSpan> spans = [];
List<RegExpMatch> links = _regExp.allMatches(text).toList();
final texts = text.split(_regExp);
final List<InlineSpan> spans = [];
final links = _regExp.allMatches(text).toList();
for (String text in texts) {
for (final text in texts) {
spans.add(TextSpan(
text: text,
));
if (links.length > 0) {
RegExpMatch match = links.removeAt(0);
Link link = Link.fromMatch(match);
if (links.isNotEmpty) {
final match = links.removeAt(0);
final link = Link.fromMatch(match);
// add the link
spans.add(
TextSpan(

View File

@ -2,13 +2,13 @@ import 'package:linkfy_text/src/enum.dart';
import 'package:linkfy_text/src/utils/regex.dart';
class Link {
String? _value;
LinkType? _type;
final String? _value;
final LinkType? _type;
String? get value => _value;
LinkType? get type => _type;
/// construct link from matched regExp
Link.fromMatch(RegExpMatch match)
: this._type = getMatchedType(match),
this._value = match.input.substring(match.start, match.end);
: _type = getMatchedType(match),
_value = match.input.substring(match.start, match.end);
}

View File

@ -6,46 +6,55 @@ String hashtagRegExp = r'(#+[a-zA-Z0-9(_)]{1,})';
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
RegExp constructRegExpFromLinkType(List<LinkType> linkTypes) {
/// construct regexp. pattern from provided link types
RegExp constructRegExpFromLinkType(List<LinkType> types) {
// default case where we always want to match url strings
if (linkTypes.length == 1 && linkTypes.first == LinkType.url) return RegExp(urlRegExp);
StringBuffer _regexBuffer = StringBuffer();
for (var i = 0; i < linkTypes.length; i++) {
final _type = linkTypes[i];
final _isLast = i == linkTypes.length - 1;
switch (_type) {
final len = types.length;
if (len == 1 && types.first == LinkType.url) {
return RegExp(urlRegExp);
}
final buffer = StringBuffer();
for (var i = 0; i < len; i++) {
final type = types[i];
final isLast = i == len - 1;
switch (type) {
case LinkType.url:
_isLast ? _regexBuffer.write("($urlRegExp)") : _regexBuffer.write("($urlRegExp)|");
isLast ? buffer.write("($urlRegExp)") : buffer.write("($urlRegExp)|");
break;
case LinkType.hashTag:
_isLast ? _regexBuffer.write("($hashtagRegExp)") : _regexBuffer.write("($hashtagRegExp)|");
isLast
? buffer.write("($hashtagRegExp)")
: buffer.write("($hashtagRegExp)|");
break;
case LinkType.userTag:
_isLast ? _regexBuffer.write("($userTagRegExp)") : _regexBuffer.write("($userTagRegExp)|");
isLast
? buffer.write("($userTagRegExp)")
: buffer.write("($userTagRegExp)|");
break;
case LinkType.email:
_isLast ? _regexBuffer.write("($emailRegExp)") : _regexBuffer.write("($emailRegExp)|");
isLast
? buffer.write("($emailRegExp)")
: buffer.write("($emailRegExp)|");
break;
default:
}
}
return RegExp(_regexBuffer.toString());
return RegExp(buffer.toString());
}
LinkType getMatchedType(RegExpMatch match) {
late LinkType _type;
late LinkType type;
if (RegExp(urlRegExp).hasMatch(match.input)) {
_type = LinkType.url;
type = LinkType.url;
} else if (RegExp(hashtagRegExp).hasMatch(match.input)) {
_type = LinkType.hashTag;
type = LinkType.hashTag;
} else if (RegExp(emailRegExp).hasMatch(match.input)) {
_type = LinkType.email;
type = LinkType.email;
} else if (RegExp(userTagRegExp).hasMatch(match.input)) {
_type = LinkType.userTag;
type = LinkType.userTag;
}
return _type;
return type;
}

View File

@ -151,6 +151,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
lint:
dependency: "direct dev"
description:
name: lint
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.3"
logging:
dependency: transitive
description:

View File

@ -15,6 +15,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
test: ^1.16.5
lint: ^1.5.3
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

View File

@ -4,17 +4,17 @@ import 'package:test/test.dart';
void main() {
group('Regular Expression', () {
/// test values
final _urlText =
// test values
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";
final _hashtagText = "#helloWorld and #dev are trending";
final _emailText =
const hashtagText = "#helloWorld and #dev are trending";
const emailText =
"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/",
"https://domain.com",
@ -28,7 +28,7 @@ void main() {
"https://sub.domain.com/Google?param=helloworld#hash",
];
final List<String> _hashtags = [
const hashtags = [
"#123",
"#H",
"#0",
@ -38,46 +38,51 @@ void main() {
"#trending_topic",
];
const userTags = [
'@helloWorld',
'@helloWorld123',
'@hello_world',
'@hello_world123',
'@hello_world_123'
];
///
test("Should match all emails", () {
_emails.forEach((e) {
bool hasMatch = RegExp(emailRegExp).hasMatch(e);
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);
});
for (final email in emails) {
expect(RegExp(emailRegExp).hasMatch(email), isTrue);
}
});
test("Should match all urls", () {
_urls.forEach((u) {
bool hasMatch = RegExp(urlRegExp).hasMatch(u);
expect(hasMatch, isTrue);
});
for (final url in urls) {
expect(RegExp(urlRegExp).hasMatch(url), isTrue);
}
});
test("Should match all hashtags", () {
_hashtags.forEach((h) {
bool hasMatch = RegExp(hashtagRegExp).hasMatch(h);
expect(hasMatch, isTrue);
for (final tag in hashtags) {
expect(RegExp(hashtagRegExp).hasMatch(tag), 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", () {
RegExp _urlRegExp = constructRegExpFromLinkType([LinkType.url]);
RegExp _hashtagRegExp = constructRegExpFromLinkType([LinkType.hashTag]);
RegExp _emailRegExp = constructRegExpFromLinkType([LinkType.email]);
RegExp _textRegExp = constructRegExpFromLinkType(
test(
"Should construct regex pattern from LinkTypes and match required output",
() {
final urlRegExp = constructRegExpFromLinkType([LinkType.url]);
final hashtagRegExp = constructRegExpFromLinkType([LinkType.hashTag]);
final emailRegExp = constructRegExpFromLinkType([LinkType.email]);
final textRegExp = constructRegExpFromLinkType(
[LinkType.url, LinkType.hashTag, LinkType.email]);
expect(_urlRegExp.allMatches(_urlText).length, 4);
expect(_hashtagRegExp.allMatches(_hashtagText).length, 2);
expect(_emailRegExp.allMatches(_emailText).length, 2);
expect(_textRegExp.allMatches(_text).length, 8);
expect(urlRegExp.allMatches(urlText).length, 4);
expect(hashtagRegExp.allMatches(hashtagText).length, 2);
expect(emailRegExp.allMatches(emailText).length, 2);
expect(textRegExp.allMatches(text).length, 8);
});
});
}