Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,22 @@ jobs:
key: pub-${{ runner.os }}-${{ hashFiles('**/pubspec.lock') }}
restore-keys: pub-${{ runner.os }}-

- name: Setup Flutter
uses: subosito/flutter-action@v2
- name: Setup Dart
uses: dart-lang/setup-dart@v1
with:
channel: stable
cache: true
sdk: stable

- name: Install dependencies
run: flutter pub get
run: dart pub get

- name: Analyze code
run: flutter analyze
run: dart analyze

- name: Check formatting
run: dart format --set-exit-if-changed .
run: dart format --output=none --set-exit-if-changed .

- name: Run tests
run: flutter test
run: dart test

- name: Pub dry run
run: flutter pub publish --dry-run
run: dart pub publish --dry-run
10 changes: 0 additions & 10 deletions .metadata

This file was deleted.

13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## 3.0.0

- **Converted from a Flutter package to a pure Dart package.** The `flutter` SDK dependency has been removed; `safe_text` now works in any Dart project (native, web, server, CLI) with no Flutter requirement.
- **`SafeTextFilter.init` is now synchronous** (`void` instead of `Future<void>`). Remove the `await` from existing call sites:
```dart
// Before (2.x)
await SafeTextFilter.init(language: Language.english);
// After (3.0.0)
SafeTextFilter.init(language: Language.english);
```
- **`SafeTextFilter.containsBadWord` is now synchronous** (`bool` instead of `Future<bool>`). Remove the `await` from existing call sites.
- **Lazy auto-initialization.** `SafeTextFilter.init` is now optional — if you never call it, the filter lazily initializes with `Language.english` on first use (`filterText` / `containsBadWord`). Explicit `init(language: ...)` still takes precedence when you need a specific language.

## 2.1.7

### Added
Expand Down
59 changes: 27 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<a href="https://pub.dev/packages/safe_text"><img src="https://img.shields.io/badge/platform-android%20%7C%20ios%20%7C%20web%20%7C%20macos%20%7C%20linux%20%7C%20windows-lightgrey" alt="platforms"></a>
</p>

A high-performance Flutter package for filtering offensive language (profanity) and detecting phone numbers. Powered by the **Aho-Corasick** algorithm for `O(N)` single-pass scanning across 80+ languages and 55,000+ curated words.
A high-performance pure Dart package for filtering offensive language (profanity) and detecting phone numbers. Powered by the **Aho-Corasick** algorithm for `O(N)` single-pass scanning across 80+ languages and 55,000+ curated words.

> 💙 Find SafeText useful? A [like on pub.dev](https://pub.dev/packages/safe_text) or [star on GitHub](https://github.com/master-wayne7/safe_text) helps others discover it.

Expand All @@ -30,7 +30,6 @@ A high-performance Flutter package for filtering offensive language (profanity)
- [`SafeTextFilter.init`](#safetextfilterinit)
- [`SafeTextFilter.isInitialized` \& `SafeTextFilter.reset`](#safetextfilterisinitialized--safetextfilterreset)
- [`SafeTextFilter.filterText`](#safetextfilterfiltertext)
- [Masking Strategies](#masking-strategies)
- [`SafeTextFilter.containsBadWord`](#safetextfiltercontainsbadword)
- [`PhoneNumberChecker.containsPhoneNumber`](#phonenumbercheckercontainsphonenumber)
- [Supported Languages](#supported-languages)
Expand All @@ -51,30 +50,31 @@ A high-performance Flutter package for filtering offensive language (profanity)
- Detects phone numbers in digits, words, mixed formats, and multiplier words (e.g., "triple five").
- Multiple masking strategies — full (`******`), partial (`f**k`), or custom replacement (`[censored]`).
- Customizable — add your own words or exclude specific phrases.
- Non-blocking — `PhoneNumberChecker` runs in a separate isolate via `compute`.
- No setup required — lazily auto-initializes with English on first use; `init` is optional.
- Non-blocking — `PhoneNumberChecker` runs in a separate isolate via `Isolate.run`.
- Works on Android, iOS, Web, macOS, Linux, and Windows.

---

## Installation

Add `safe_text` to your project using the Flutter CLI:
Add `safe_text` to your project using the Dart CLI:

```bash
flutter pub add safe_text
dart pub add safe_text
```

Or manually add it to your `pubspec.yaml`:

```yaml
dependencies:
safe_text: ^2.1.7
safe_text: ^3.0.0
```

Then run:

```bash
flutter pub get
dart pub get
```

---
Expand All @@ -85,8 +85,10 @@ flutter pub get
import 'package:safe_text/safe_text.dart';

void main() async {
// Initialize once at app startup
await SafeTextFilter.init(language: Language.english);
// Optional: initialize once at app startup with a specific language.
// If you skip this, the filter lazily auto-initializes with English on
// first use.
SafeTextFilter.init(language: Language.english);

// Filter profanity (full masking — default)
final clean = SafeTextFilter.filterText(text: "What the f@ck!");
Expand All @@ -107,7 +109,7 @@ void main() async {
print(custom); // "What the [censored]!"

// Check for bad words
final hasBad = await SafeTextFilter.containsBadWord(text: "Some bad input");
final hasBad = SafeTextFilter.containsBadWord(text: "Some bad input");
print(hasBad); // true or false

// Detect phone numbers
Expand All @@ -124,17 +126,17 @@ void main() async {

### `SafeTextFilter.init`

Must be called **once** before using `filterText` or `containsBadWord`. Builds the Aho-Corasick trie from the selected word list(s).
**Optional.** Builds the Aho-Corasick trie from the selected word list(s). If you never call it, the filter lazily auto-initializes with `Language.english` on first use of `filterText` / `containsBadWord`. Call it explicitly when you want a specific language or combination.

```dart
// Single language
await SafeTextFilter.init(language: Language.english);
SafeTextFilter.init(language: Language.english);

// Custom combination
await SafeTextFilter.init(languages: [Language.english, Language.hindi, Language.spanish]);
SafeTextFilter.init(languages: [Language.english, Language.hindi, Language.spanish]);

// All 75+ languages
await SafeTextFilter.init(language: Language.all);
SafeTextFilter.init(language: Language.all);
```

| Parameter | Type | Default | Description |
Expand All @@ -146,17 +148,12 @@ await SafeTextFilter.init(language: Language.all);

### `SafeTextFilter.isInitialized` & `SafeTextFilter.reset`

Check initialization status or reset loaded word lists dynamically (e.g., when switching languages):
Check initialization status or reset loaded word lists dynamically (e.g., when switching languages). Because `init` auto-initializes on first use, you generally don't need to guard calls with `isInitialized` — but it's available if you want to check, and `reset()` lets you reload with a different language:

```dart
// Check if initialized
if (!SafeTextFilter.isInitialized) {
await SafeTextFilter.init(language: Language.english);
}

// Reset state to reload with a different language
SafeTextFilter.reset();
await SafeTextFilter.init(language: Language.spanish);
SafeTextFilter.init(language: Language.spanish);
```

---
Expand Down Expand Up @@ -219,7 +216,7 @@ String custom = SafeTextFilter.filterText(
Asynchronous. Returns `true` if the text contains at least one filtered word.

```dart
bool hasBadWord = await SafeTextFilter.containsBadWord(
bool hasBadWord = SafeTextFilter.containsBadWord(
text: "Don't be a pendejo",
extraWords: ["badterm"], // optional
excludedWords: ["pend"], // optional
Expand All @@ -238,7 +235,7 @@ bool hasBadWord = await SafeTextFilter.containsBadWord(

### `PhoneNumberChecker.containsPhoneNumber`

Asynchronous. Runs in a **separate isolate** via Flutter's `compute` function so it never blocks the UI thread.
Asynchronous. Runs in a **separate isolate** via Dart's `Isolate.run` so it never blocks the calling thread.

Detects phone numbers expressed as:
- Pure digits: `9783444`
Expand Down Expand Up @@ -379,9 +376,9 @@ The original `SafeText` class is still available but marked `@Deprecated`. It in

| v1.x | v2.0.0 |
|---|---|
| `await SafeTextFilter.init(...)` | Requiredcall once at startup |
| `SafeTextFilter.init(...)` | Optionalauto-initializes with English on first use |
| `SafeText.filterText(text: ...)` | `SafeTextFilter.filterText(text: ...)` |
| `await SafeText.containsBadWord(text: ...)` | `await SafeTextFilter.containsBadWord(text: ...)` |
| `await SafeText.containsBadWord(text: ...)` | `SafeTextFilter.containsBadWord(text: ...)` |
| `await SafeText.containsPhoneNumber(text: ...)` | `await PhoneNumberChecker.containsPhoneNumber(text: ...)` |

**Before:**
Expand All @@ -392,19 +389,17 @@ bool bad = await SafeText.containsBadWord(text: "some input");

**After:**
```dart
// v2.0.0 — init once, then use anywhere
await SafeTextFilter.init(language: Language.english); // once, e.g. in main()
bool bad = await SafeTextFilter.containsBadWord(text: "some input");
// v2.0.0 — init is optional; auto-initializes with English on first use
SafeTextFilter.init(language: Language.english); // optional, e.g. for a specific language
bool bad = SafeTextFilter.containsBadWord(text: "some input");
```

---

## Limitations

- **`SafeTextFilter.init` must be called before use.** Calling `filterText` or `containsBadWord` before `init` will fall back to a small built-in word list without the full multilingual dataset.
- **Phone number detection is English-word based.** Words like "nine", "triple", etc. are English only — the detector does not parse written numbers in other languages.
- **False positives on technical terms.** Short words in the filter list may match substrings of unrelated technical terms. Use `excludedWords` to suppress known false positives.
- **`Language.all` increases init time.** Loading all 75+ language files is I/O-heavy. For most apps a targeted language list is faster.

---

Expand All @@ -417,8 +412,8 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for th
3. Add tests for any new behaviour.
4. Run checks before submitting:
```bash
flutter analyze
flutter test
dart analyze
dart test
```
5. Open a pull request targeting `develop`. Ensure CI passes.

Expand Down
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
include: package:flutter_lints/flutter.yaml
include: package:lints/recommended.yaml

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
Loading
Loading