├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example └── slugify_example.dart ├── lib ├── slugify.dart └── src │ ├── replacements.dart │ └── slugify.dart ├── pubspec.lock ├── pubspec.yaml └── test └── slugify_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Don’t commit the following directories created by pub. 2 | build/ 3 | .dart_tool/ 4 | .packages 5 | build/ 6 | 7 | # Or the files created by dart2js. 8 | *.dart.js 9 | *.dart.precompiled.js 10 | *.js_ 11 | *.js.deps 12 | *.js.map 13 | 14 | # Include when developing application packages. 15 | # pubspec.lock 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [2.0.0] - 2021-03-28 8 | ### Changed 9 | - Publish null-safe version 10 | - Rename top-level definition to `slugify` from `Slugify` 11 | - Conform to effective dart lint rules 12 | 13 | ## [1.0.0] - 2019-04-23 14 | ### Added 15 | - Environment to pubspec 16 | - Ampersand to replacements 17 | - Vietnamese replacements (thanks @lyquocnam) 18 | 19 | ### Changed 20 | - Update package to Dart 2 21 | - Replace `unittest` package with `test` 22 | - Refactor class to top-level function 23 | - Rewrite tests 24 | - Add version constraint for test package 25 | - Code formatting with dartfmt 26 | 27 | ## [0.1.1] 28 | ### Changed 29 | - Set return type on `Slugify.slugify()` 30 | 31 | ## [0.1.0] 32 | ### Added 33 | - documentation 34 | 35 | ## [0.0.2] 36 | ### Added 37 | - Unit tests 38 | - Examples 39 | 40 | ## [0.0.1] 41 | ### Added 42 | - Initial commit 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 izolate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # slugify 2 | 3 | Converts any `String` to a **slug**. Useful for URLs, filenames, IDs, and more. 4 | 5 | ## Features 6 | 7 | * Multi-language support 8 | * Removes unfriendly characters 9 | * Approximates replacements for characters not in the Latin alphabet 10 | * Configurable options 11 | * Null safe with Dart 2.12 12 | 13 | ## Usage 14 | 15 | ```dart 16 | import 'package:slugify/slugify.dart'; 17 | 18 | // Use with default options. 19 | var slug = slugify('Hello, World! Foo Bar'); 20 | print(slug); // hello-world-foo-bar 21 | 22 | // Use with custom options. 23 | var slug2 = slugify('Hello, World! Foo Bar', lowercase: false, delimiter: '🙂'); 24 | print(slug2) // Hello🙂World🙂Foo🙂Bar 25 | ``` 26 | 27 | ### Options 28 | 29 | Name | Type | Default | Description 30 | --- | --- | --- | --- 31 | `delimiter` | `String` | `"-"` | Separator between words 32 | `lowercase` | `bool` | `true` | Convert text to lowercase 33 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:effective_dart/analysis_options.yaml 2 | -------------------------------------------------------------------------------- /example/slugify_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:slugify/slugify.dart'; 2 | 3 | void main() { 4 | // Slugify with default config. 5 | var slug1 = slugify('Hello, world!'); 6 | print(slug1); // 'hello-world' 7 | 8 | // Set a custom delimiter. 9 | var slug2 = slugify('Some prefer snake case', delimiter: '_'); 10 | print(slug2); // 'some_prefer_snake_case' 11 | 12 | // Preserve the original case. 13 | var slug3 = slugify('BREAKING NEWS! The world is ending!', lowercase: false); 14 | print(slug3); // 'BREAKING-NEWS-The-world-is-ending' 15 | 16 | // Normalize to latin characters. 17 | var slug4 = slugify("C'est déjà l'été."); 18 | print(slug4); // 'cest-deja-lete' 19 | } 20 | -------------------------------------------------------------------------------- /lib/slugify.dart: -------------------------------------------------------------------------------- 1 | /// Slugify a string 2 | library slugify; 3 | 4 | export 'src/slugify.dart' show slugify; 5 | -------------------------------------------------------------------------------- /lib/src/replacements.dart: -------------------------------------------------------------------------------- 1 | /// List of common character replacements. 2 | const replacements = { 3 | '¹': '1', 4 | '²': '2', 5 | '³': '3', 6 | 'º': 'o', 7 | '°': '0', 8 | 'æ': 'ae', 9 | 'ǽ': 'ae', 10 | 'À': 'A', 11 | 'Á': 'A', 12 | 'Â': 'A', 13 | 'Ã': 'A', 14 | 'Å': 'A', 15 | 'Ǻ': 'A', 16 | 'Ă': 'A', 17 | 'Ǎ': 'A', 18 | 'Ạ': 'A', 19 | 'Ả': 'A', 20 | 'ả': 'a', 21 | 'ạ': 'a', 22 | 'Ầ': 'A', 23 | 'ầ': 'a', 24 | 'Ẩ': 'A', 25 | 'ẩ': 'a', 26 | 'Ẫ': 'A', 27 | 'ẫ': 'a', 28 | 'Ậ': 'A', 29 | 'ậ': 'a', 30 | 'Ắ': 'A', 31 | 'ắ': 'a', 32 | 'Ằ': 'Ằ', 33 | 'ằ': 'ằ', 34 | 'Ẳ': 'A', 35 | 'ẳ': 'a', 36 | 'Ẵ': 'A', 37 | 'ẵ': 'a', 38 | 'Ặ': 'A', 39 | 'ặ': 'a', 40 | 'Æ': 'AE', 41 | 'Ǽ': 'AE', 42 | 'à': 'a', 43 | 'á': 'a', 44 | 'â': 'a', 45 | 'ã': 'a', 46 | 'å': 'a', 47 | 'ǻ': 'a', 48 | 'ă': 'a', 49 | 'ǎ': 'a', 50 | 'ª': 'a', 51 | '@': 'at', 52 | '&': 'and', 53 | 'Ĉ': 'CX', 54 | 'Ċ': 'C', 55 | 'ĉ': 'cx', 56 | 'ċ': 'c', 57 | '©': 'c', 58 | 'Ð': 'Dj', 59 | 'Đ': 'Dj', 60 | 'ð': 'dj', 61 | 'đ': 'dj', 62 | 'È': 'E', 63 | 'É': 'E', 64 | 'Ê': 'E', 65 | 'Ë': 'E', 66 | 'Ĕ': 'E', 67 | 'Ė': 'E', 68 | 'è': 'e', 69 | 'é': 'e', 70 | 'ê': 'e', 71 | 'ë': 'e', 72 | 'ĕ': 'e', 73 | 'ė': 'e', 74 | 'Ệ': 'E', 75 | 'ệ': 'e', 76 | 'Ể': 'E', 77 | 'ể': 'e', 78 | 'Ẹ': 'E', 79 | 'ẻ': 'e', 80 | 'Ẻ': 'E', 81 | 'ẽ': 'e', 82 | 'Ẽ': 'E', 83 | 'ễ': 'e', 84 | 'Ễ': 'E', 85 | 'ẹ': 'e', 86 | 'ƒ': 'f', 87 | 'Ĝ': 'GX', 88 | 'Ġ': 'G', 89 | 'ĝ': 'gx', 90 | 'ġ': 'g', 91 | 'Ĥ': 'HX', 92 | 'Ħ': 'H', 93 | 'ĥ': 'hx', 94 | 'ħ': 'h', 95 | 'Ì': 'I', 96 | 'Í': 'I', 97 | 'Î': 'I', 98 | 'Ï': 'I', 99 | 'Ĩ': 'I', 100 | 'Ĭ': 'I', 101 | 'Ǐ': 'I', 102 | 'Į': 'I', 103 | 'IJ': 'IJ', 104 | 'ì': 'i', 105 | 'í': 'i', 106 | 'î': 'i', 107 | 'ï': 'i', 108 | 'ĩ': 'i', 109 | 'ĭ': 'i', 110 | 'ǐ': 'i', 111 | 'į': 'i', 112 | 'Ỉ': 'I', 113 | 'ỉ': 'i', 114 | 'Ị': 'I', 115 | 'ị': 'i', 116 | 'ij': 'ij', 117 | 'Ĵ': 'JX', 118 | 'ĵ': 'jx', 119 | 'Ĺ': 'L', 120 | 'Ľ': 'L', 121 | 'Ŀ': 'L', 122 | 'ĺ': 'l', 123 | 'ľ': 'l', 124 | 'ŀ': 'l', 125 | 'Ñ': 'N', 126 | 'ñ': 'n', 127 | 'ʼn': 'n', 128 | 'Ò': 'O', 129 | 'Ô': 'O', 130 | 'Õ': 'O', 131 | 'Ō': 'O', 132 | 'Ŏ': 'O', 133 | 'Ǒ': 'O', 134 | 'Ő': 'O', 135 | 'Ơ': 'O', 136 | 'Ø': 'O', 137 | 'Ǿ': 'O', 138 | 'Œ': 'OE', 139 | 'ò': 'o', 140 | 'ô': 'o', 141 | 'õ': 'o', 142 | 'ō': 'o', 143 | 'ŏ': 'o', 144 | 'ǒ': 'o', 145 | 'ő': 'o', 146 | 'ơ': 'o', 147 | 'ø': 'o', 148 | 'ǿ': 'o', 149 | 'Ọ': 'O', 150 | 'ọ': 'o', 151 | 'Ổ': 'O', 152 | 'ỗ': 'o', 153 | 'Ỗ': 'o', 154 | 'ổ': 'o', 155 | 'Ộ': 'O', 156 | 'ộ': 'o', 157 | 'ợ': 'o', 158 | 'Ợ': 'o', 159 | 'Ở': 'O', 160 | 'ở': 'o', 161 | 'Ỡ': 'O', 162 | 'ỡ': 'o', 163 | 'œ': 'oe', 164 | 'Ŕ': 'R', 165 | 'Ŗ': 'R', 166 | 'ŕ': 'r', 167 | 'ŗ': 'r', 168 | 'Ŝ': 'SX', 169 | 'Ș': 'S', 170 | 'ŝ': 'sx', 171 | 'ș': 's', 172 | 'ſ': 's', 173 | 'Ţ': 'T', 174 | 'Ț': 'T', 175 | 'Ŧ': 'T', 176 | 'Þ': 'TH', 177 | 'ţ': 't', 178 | 'ț': 't', 179 | 'ŧ': 't', 180 | 'þ': 'th', 181 | 'Ù': 'U', 182 | 'Ú': 'U', 183 | 'Û': 'U', 184 | 'Ũ': 'U', 185 | 'Ŭ': 'UX', 186 | 'Ű': 'U', 187 | 'Ų': 'U', 188 | 'Ư': 'U', 189 | 'Ǔ': 'U', 190 | 'Ǖ': 'U', 191 | 'Ǘ': 'U', 192 | 'Ǚ': 'U', 193 | 'Ǜ': 'U', 194 | 'ù': 'u', 195 | 'ú': 'u', 196 | 'û': 'u', 197 | 'ũ': 'u', 198 | 'ŭ': 'ux', 199 | 'ű': 'u', 200 | 'ų': 'u', 201 | 'ư': 'u', 202 | 'ǔ': 'u', 203 | 'ǖ': 'u', 204 | 'ǘ': 'u', 205 | 'ǚ': 'u', 206 | 'ǜ': 'u', 207 | 'Ụ': 'U', 208 | 'Ủ': 'U', 209 | 'ủ': 'u', 210 | 'ụ': 'u', 211 | 'Ŵ': 'W', 212 | 'ŵ': 'w', 213 | 'Ý': 'Y', 214 | 'Ÿ': 'Y', 215 | 'Ŷ': 'Y', 216 | 'ý': 'y', 217 | 'ÿ': 'y', 218 | 'ŷ': 'y', 219 | 'Ъ': '', 220 | 'Ь': '', 221 | 'А': 'A', 222 | 'Б': 'B', 223 | 'Ц': 'C', 224 | 'Ч': 'Ch', 225 | 'Д': 'D', 226 | 'Е': 'E', 227 | 'Ё': 'E', 228 | 'Э': 'E', 229 | 'Ф': 'F', 230 | 'Г': 'G', 231 | 'Х': 'H', 232 | 'И': 'I', 233 | 'Й': 'J', 234 | 'Я': 'Ja', 235 | 'Ю': 'Ju', 236 | 'К': 'K', 237 | 'Л': 'L', 238 | 'М': 'M', 239 | 'Н': 'N', 240 | 'О': 'O', 241 | 'П': 'P', 242 | 'Р': 'R', 243 | 'С': 'S', 244 | 'Ш': 'Sh', 245 | 'Щ': 'Shch', 246 | 'Т': 'T', 247 | 'У': 'U', 248 | 'В': 'V', 249 | 'Ы': 'Y', 250 | 'З': 'Z', 251 | 'Ж': 'Zh', 252 | 'ъ': '', 253 | 'ь': '', 254 | 'а': 'a', 255 | 'б': 'b', 256 | 'ц': 'c', 257 | 'ч': 'ch', 258 | 'д': 'd', 259 | 'е': 'e', 260 | 'ё': 'e', 261 | 'э': 'e', 262 | 'ф': 'f', 263 | 'г': 'g', 264 | 'х': 'h', 265 | 'и': 'i', 266 | 'й': 'j', 267 | 'я': 'ja', 268 | 'ю': 'ju', 269 | 'к': 'k', 270 | 'л': 'l', 271 | 'м': 'm', 272 | 'н': 'n', 273 | 'о': 'o', 274 | 'п': 'p', 275 | 'р': 'r', 276 | 'с': 's', 277 | 'ш': 'sh', 278 | 'щ': 'shch', 279 | 'т': 't', 280 | 'у': 'u', 281 | 'в': 'v', 282 | 'ы': 'y', 283 | 'з': 'z', 284 | 'ж': 'zh', 285 | 'Ä': 'AE', 286 | 'Ö': 'OE', 287 | 'Ü': 'UE', 288 | 'ß': 'ss', 289 | 'ä': 'ae', 290 | 'ö': 'oe', 291 | 'ü': 'ue', 292 | 'Ç': 'C', 293 | 'Ğ': 'G', 294 | 'İ': 'I', 295 | 'Ş': 'S', 296 | 'ç': 'c', 297 | 'ğ': 'g', 298 | 'ı': 'i', 299 | 'ş': 's', 300 | 'Ā': 'A', 301 | 'Ē': 'E', 302 | 'Ģ': 'G', 303 | 'Ī': 'I', 304 | 'Ķ': 'K', 305 | 'Ļ': 'L', 306 | 'Ņ': 'N', 307 | 'Ū': 'U', 308 | 'ā': 'a', 309 | 'ē': 'e', 310 | 'ģ': 'g', 311 | 'ī': 'i', 312 | 'ķ': 'k', 313 | 'ļ': 'l', 314 | 'ņ': 'n', 315 | 'ū': 'u', 316 | 'Ґ': 'G', 317 | 'І': 'I', 318 | 'Ї': 'Ji', 319 | 'Є': 'Ye', 320 | 'ґ': 'g', 321 | 'і': 'i', 322 | 'ї': 'ji', 323 | 'є': 'ye', 324 | 'Č': 'C', 325 | 'Ď': 'Dj', 326 | 'Ě': 'E', 327 | 'Ň': 'N', 328 | 'Ř': 'R', 329 | 'Š': 'S', 330 | 'Ť': 'T', 331 | 'Ů': 'U', 332 | 'Ž': 'Z', 333 | 'č': 'c', 334 | 'ď': 'dj', 335 | 'ě': 'e', 336 | 'ň': 'n', 337 | 'ř': 'r', 338 | 'š': 's', 339 | 'ť': 't', 340 | 'ů': 'u', 341 | 'ž': 'z', 342 | 'Ą': 'A', 343 | 'Ć': 'C', 344 | 'Ę': 'E', 345 | 'Ł': 'L', 346 | 'Ń': 'N', 347 | 'Ó': 'O', 348 | 'Ś': 'S', 349 | 'Ź': 'Z', 350 | 'Ż': 'Z', 351 | 'ą': 'a', 352 | 'ć': 'c', 353 | 'ę': 'e', 354 | 'ł': 'l', 355 | 'ń': 'n', 356 | 'ó': 'o', 357 | 'ś': 's', 358 | 'ź': 'z', 359 | 'ż': 'z', 360 | 'Α': 'A', 361 | 'Β': 'B', 362 | 'Γ': 'G', 363 | 'Δ': 'D', 364 | 'Ε': 'E', 365 | 'Ζ': 'Z', 366 | 'Η': 'E', 367 | 'Θ': 'Th', 368 | 'Ι': 'I', 369 | 'Κ': 'K', 370 | 'Λ': 'L', 371 | 'Μ': 'M', 372 | 'Ν': 'N', 373 | 'Ξ': 'X', 374 | 'Ο': 'O', 375 | 'Π': 'P', 376 | 'Ρ': 'R', 377 | 'Σ': 'S', 378 | 'Τ': 'T', 379 | 'Υ': 'Y', 380 | 'Ỷ': 'Y', 381 | 'ỷ': 'y', 382 | 'Ỹ': 'Y', 383 | 'ỹ': 'y', 384 | 'Ỵ': 'Y', 385 | 'ỵ': 'y', 386 | 'Φ': 'Ph', 387 | 'Χ': 'Ch', 388 | 'Ψ': 'Ps', 389 | 'Ω': 'O', 390 | 'Ϊ': 'I', 391 | 'Ϋ': 'Y', 392 | 'ά': 'a', 393 | 'έ': 'e', 394 | 'ή': 'e', 395 | 'ί': 'i', 396 | 'ΰ': 'Y', 397 | 'α': 'a', 398 | 'β': 'b', 399 | 'γ': 'g', 400 | 'δ': 'd', 401 | 'ε': 'e', 402 | 'ζ': 'z', 403 | 'η': 'e', 404 | 'θ': 'th', 405 | 'ι': 'i', 406 | 'κ': 'k', 407 | 'λ': 'l', 408 | 'μ': 'm', 409 | 'ν': 'n', 410 | 'ξ': 'x', 411 | 'ο': 'o', 412 | 'π': 'p', 413 | 'ρ': 'r', 414 | 'ς': 's', 415 | 'σ': 's', 416 | 'τ': 't', 417 | 'υ': 'y', 418 | 'φ': 'ph', 419 | 'χ': 'ch', 420 | 'ψ': 'ps', 421 | 'ω': 'o', 422 | 'ϊ': 'i', 423 | 'ϋ': 'y', 424 | 'ό': 'o', 425 | 'ύ': 'y', 426 | 'ώ': 'o', 427 | 'ϐ': 'b', 428 | 'ϑ': 'th', 429 | 'ϒ': 'Y', 430 | 'أ': 'a', 431 | 'ب': 'b', 432 | 'ت': 't', 433 | 'ث': 'th', 434 | 'ج': 'g', 435 | 'ح': 'h', 436 | 'خ': 'kh', 437 | 'د': 'd', 438 | 'ذ': 'th', 439 | 'ر': 'r', 440 | 'ز': 'z', 441 | 'س': 's', 442 | 'ش': 'sh', 443 | 'ص': 's', 444 | 'ض': 'd', 445 | 'ط': 't', 446 | 'ظ': 'th', 447 | 'ع': 'aa', 448 | 'غ': 'gh', 449 | 'ف': 'f', 450 | 'ق': 'k', 451 | 'ك': 'k', 452 | 'ل': 'l', 453 | 'م': 'm', 454 | 'ن': 'n', 455 | 'ه': 'h', 456 | 'و': 'o', 457 | 'ي': 'y' 458 | }; 459 | -------------------------------------------------------------------------------- /lib/src/slugify.dart: -------------------------------------------------------------------------------- 1 | import 'replacements.dart'; 2 | 3 | final _dupeSpaceRegExp = RegExp(r'\s{2,}'); 4 | final _punctuationRegExp = RegExp(r'[^\w\s-]'); 5 | 6 | /// Converts [text] to a slug [String] separated by the [delimiter]. 7 | String slugify(String text, {String delimiter = '-', bool lowercase = true}) { 8 | // Trim leading and trailing whitespace. 9 | var slug = text.trim(); 10 | 11 | // Make the text lowercase (optional). 12 | if (lowercase) { 13 | slug = slug.toLowerCase(); 14 | } 15 | 16 | // Substitute characters for their latin equivalent. 17 | replacements.forEach((k, v) => slug = slug.replaceAll(k, v)); 18 | 19 | slug = slug 20 | // Condense whitespaces to 1 space. 21 | .replaceAll(_dupeSpaceRegExp, ' ') 22 | // Remove punctuation. 23 | .replaceAll(_punctuationRegExp, '') 24 | // Replace space with the delimiter. 25 | .replaceAll(' ', delimiter); 26 | 27 | return slug; 28 | } 29 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "16.0.0" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.0" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.0.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.5.0" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.1.0" 39 | charcode: 40 | dependency: transitive 41 | description: 42 | name: charcode 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.2.0" 46 | cli_util: 47 | dependency: transitive 48 | description: 49 | name: cli_util 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.3.0" 53 | collection: 54 | dependency: transitive 55 | description: 56 | name: collection 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.15.0" 60 | convert: 61 | dependency: transitive 62 | description: 63 | name: convert 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "3.0.0" 67 | coverage: 68 | dependency: transitive 69 | description: 70 | name: coverage 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "0.15.2" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "3.0.0" 81 | effective_dart: 82 | dependency: "direct dev" 83 | description: 84 | name: effective_dart 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "1.3.1" 88 | file: 89 | dependency: transitive 90 | description: 91 | name: file 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "6.1.0" 95 | glob: 96 | dependency: transitive 97 | description: 98 | name: glob 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "2.0.0" 102 | http_multi_server: 103 | dependency: transitive 104 | description: 105 | name: http_multi_server 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "2.2.0" 109 | http_parser: 110 | dependency: transitive 111 | description: 112 | name: http_parser 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "4.0.0" 116 | io: 117 | dependency: transitive 118 | description: 119 | name: io 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "0.3.5" 123 | js: 124 | dependency: transitive 125 | description: 126 | name: js 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "0.6.3" 130 | logging: 131 | dependency: transitive 132 | description: 133 | name: logging 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "1.0.0" 137 | matcher: 138 | dependency: transitive 139 | description: 140 | name: matcher 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "0.12.10" 144 | meta: 145 | dependency: transitive 146 | description: 147 | name: meta 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "1.3.0" 151 | mime: 152 | dependency: transitive 153 | description: 154 | name: mime 155 | url: "https://pub.dartlang.org" 156 | source: hosted 157 | version: "1.0.0" 158 | node_preamble: 159 | dependency: transitive 160 | description: 161 | name: node_preamble 162 | url: "https://pub.dartlang.org" 163 | source: hosted 164 | version: "1.4.13" 165 | package_config: 166 | dependency: transitive 167 | description: 168 | name: package_config 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "2.0.0" 172 | path: 173 | dependency: transitive 174 | description: 175 | name: path 176 | url: "https://pub.dartlang.org" 177 | source: hosted 178 | version: "1.8.0" 179 | pedantic: 180 | dependency: transitive 181 | description: 182 | name: pedantic 183 | url: "https://pub.dartlang.org" 184 | source: hosted 185 | version: "1.10.0" 186 | pool: 187 | dependency: transitive 188 | description: 189 | name: pool 190 | url: "https://pub.dartlang.org" 191 | source: hosted 192 | version: "1.5.0" 193 | pub_semver: 194 | dependency: transitive 195 | description: 196 | name: pub_semver 197 | url: "https://pub.dartlang.org" 198 | source: hosted 199 | version: "2.0.0" 200 | shelf: 201 | dependency: transitive 202 | description: 203 | name: shelf 204 | url: "https://pub.dartlang.org" 205 | source: hosted 206 | version: "1.0.0" 207 | shelf_packages_handler: 208 | dependency: transitive 209 | description: 210 | name: shelf_packages_handler 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "2.0.1" 214 | shelf_static: 215 | dependency: transitive 216 | description: 217 | name: shelf_static 218 | url: "https://pub.dartlang.org" 219 | source: hosted 220 | version: "0.2.9+2" 221 | shelf_web_socket: 222 | dependency: transitive 223 | description: 224 | name: shelf_web_socket 225 | url: "https://pub.dartlang.org" 226 | source: hosted 227 | version: "0.2.4+1" 228 | source_map_stack_trace: 229 | dependency: transitive 230 | description: 231 | name: source_map_stack_trace 232 | url: "https://pub.dartlang.org" 233 | source: hosted 234 | version: "2.1.0" 235 | source_maps: 236 | dependency: transitive 237 | description: 238 | name: source_maps 239 | url: "https://pub.dartlang.org" 240 | source: hosted 241 | version: "0.10.10" 242 | source_span: 243 | dependency: transitive 244 | description: 245 | name: source_span 246 | url: "https://pub.dartlang.org" 247 | source: hosted 248 | version: "1.8.1" 249 | stack_trace: 250 | dependency: transitive 251 | description: 252 | name: stack_trace 253 | url: "https://pub.dartlang.org" 254 | source: hosted 255 | version: "1.10.0" 256 | stream_channel: 257 | dependency: transitive 258 | description: 259 | name: stream_channel 260 | url: "https://pub.dartlang.org" 261 | source: hosted 262 | version: "2.1.0" 263 | string_scanner: 264 | dependency: transitive 265 | description: 266 | name: string_scanner 267 | url: "https://pub.dartlang.org" 268 | source: hosted 269 | version: "1.1.0" 270 | term_glyph: 271 | dependency: transitive 272 | description: 273 | name: term_glyph 274 | url: "https://pub.dartlang.org" 275 | source: hosted 276 | version: "1.2.0" 277 | test: 278 | dependency: "direct dev" 279 | description: 280 | name: test 281 | url: "https://pub.dartlang.org" 282 | source: hosted 283 | version: "1.16.4" 284 | test_api: 285 | dependency: transitive 286 | description: 287 | name: test_api 288 | url: "https://pub.dartlang.org" 289 | source: hosted 290 | version: "0.2.19" 291 | test_core: 292 | dependency: transitive 293 | description: 294 | name: test_core 295 | url: "https://pub.dartlang.org" 296 | source: hosted 297 | version: "0.3.14" 298 | typed_data: 299 | dependency: transitive 300 | description: 301 | name: typed_data 302 | url: "https://pub.dartlang.org" 303 | source: hosted 304 | version: "1.3.0" 305 | vm_service: 306 | dependency: transitive 307 | description: 308 | name: vm_service 309 | url: "https://pub.dartlang.org" 310 | source: hosted 311 | version: "6.1.0+1" 312 | watcher: 313 | dependency: transitive 314 | description: 315 | name: watcher 316 | url: "https://pub.dartlang.org" 317 | source: hosted 318 | version: "1.0.0" 319 | web_socket_channel: 320 | dependency: transitive 321 | description: 322 | name: web_socket_channel 323 | url: "https://pub.dartlang.org" 324 | source: hosted 325 | version: "2.0.0" 326 | webkit_inspection_protocol: 327 | dependency: transitive 328 | description: 329 | name: webkit_inspection_protocol 330 | url: "https://pub.dartlang.org" 331 | source: hosted 332 | version: "0.7.5" 333 | yaml: 334 | dependency: transitive 335 | description: 336 | name: yaml 337 | url: "https://pub.dartlang.org" 338 | source: hosted 339 | version: "3.0.0" 340 | sdks: 341 | dart: ">=2.12.0 <3.0.0" 342 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: slugify 2 | version: 2.0.0 3 | description: >- 4 | Converts a string into a slug. 5 | Useful for URLs, filenames, IDs, and more. 6 | author: izolate 7 | homepage: https://github.com/izolate/slugify 8 | documentation: https://github.com/izolate/slugify/blob/master/README.md 9 | environment: 10 | sdk: '>=2.12.0 <3.0.0' 11 | dev_dependencies: 12 | test: ^1.16.4 13 | effective_dart: ^1.0.0 14 | -------------------------------------------------------------------------------- /test/slugify_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart' show equals, expect, test; 2 | import 'package:slugify/slugify.dart'; 3 | 4 | void main() { 5 | test('returns a slugified string with default options', () { 6 | var result = slugify('Hello, world! This is a test'); 7 | var expected = 'hello-world-this-is-a-test'; 8 | expect(result, equals(expected)); 9 | }); 10 | 11 | test('preserves case when lowercase is false', () { 12 | var result = slugify('CAPS LOCK IS STUCK ON', lowercase: false); 13 | var expected = 'CAPS-LOCK-IS-STUCK-ON'; 14 | expect(result, equals(expected)); 15 | }); 16 | 17 | test('supports a custom delimiter', () { 18 | var result = slugify('The tests are all passing', delimiter: '👏'); 19 | var expected = 'the👏tests👏are👏all👏passing'; 20 | expect(result, equals(expected)); 21 | }); 22 | 23 | test('normalizes text to the latin character set', () { 24 | var result = slugify('Nín hǎo. Wǒ shì zhōng guó rén'); 25 | var expected = 'nin-hao-wo-shi-zhong-guo-ren'; 26 | expect(result, equals(expected)); 27 | }); 28 | 29 | test('trims leading/trailing whitespace', () { 30 | var result = slugify(' too many spaces '); 31 | var expected = 'too-many-spaces'; 32 | expect(result, equals(expected)); 33 | }); 34 | 35 | test('removes or replaces punctuation', () { 36 | var result = slugify('("foo!*") <&> ~[^b@r!#=];'); 37 | var expected = 'foo-and-batr'; 38 | expect(result, equals(expected)); 39 | }); 40 | } 41 | --------------------------------------------------------------------------------