slugcopy 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +13 -0
  2. package/package.json +2 -2
  3. package/test.js +101 -6
package/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  - 🛠 **Customizable**: Choose your separator, handle camelCase, and more.
14
14
  - 📦 **Modern**: Built with modern Node.js standards.
15
15
  - 🌐 **International**: Handles special characters (e.g., `Déjà Vu!` -> `deja-vu`).
16
+ - ✅ **Comprehensive**: Handles edge cases like parentheses, brackets, quotes, newlines, and more.
16
17
 
17
18
  ## Install
18
19
 
@@ -61,6 +62,18 @@ $ slugcopy "Just Print This" --no-copy
61
62
  # Clipboard: (unchanged)
62
63
  ```
63
64
 
65
+ ## Important Notes
66
+
67
+ **Shell Special Characters**: When using shell special characters (parentheses, brackets, quotes, etc.), always wrap your input in quotes:
68
+
69
+ ```bash
70
+ # ✅ Correct - wrapped in quotes
71
+ $ slugcopy "Text with (parentheses) and [brackets]"
72
+
73
+ # ❌ Incorrect - will cause shell parsing errors
74
+ $ slugcopy Text with (parentheses) and [brackets]
75
+ ```
76
+
64
77
  ## Related
65
78
 
66
79
  - [slugify-cli](https://github.com/sindresorhus/slugify-cli) - The original inspiration for this project.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slugcopy",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Slugify strings and copy to clipboard",
5
5
  "main": "cli.js",
6
6
  "scripts": {
@@ -47,4 +47,4 @@
47
47
  "ava": "6.4.1",
48
48
  "execa": "9.6.1"
49
49
  }
50
- }
50
+ }
package/test.js CHANGED
@@ -1,27 +1,122 @@
1
1
  import test from 'ava';
2
- import {execa} from 'execa';
2
+ import { execa } from 'execa';
3
3
 
4
4
  test('main', async t => {
5
- const {stdout} = await execa('./cli.js', ['Déjà Vu!']);
5
+ const { stdout } = await execa('./cli.js', ['Déjà Vu!']);
6
6
  t.is(stdout.split("\n")[0], 'deja-vu');
7
7
  });
8
8
 
9
9
  test('separator', async t => {
10
- const {stdout} = await execa('./cli.js', ['Like a Boss', '--separator=_']);
10
+ const { stdout } = await execa('./cli.js', ['Like a Boss', '--separator=_']);
11
11
  t.is(stdout.split("\n")[0], 'like_a_boss');
12
12
  });
13
13
 
14
14
  test('lowercase', async t => {
15
- const {stdout} = await execa('./cli.js', ['Déjà Vu!', '--no-lowercase']);
15
+ const { stdout } = await execa('./cli.js', ['Déjà Vu!', '--no-lowercase']);
16
16
  t.is(stdout.split("\n")[0], 'Deja-Vu');
17
17
  });
18
18
 
19
19
  test('decamelize', async t => {
20
- const {stdout} = await execa('./cli.js', ['fooBar', '--no-decamelize']);
20
+ const { stdout } = await execa('./cli.js', ['fooBar', '--no-decamelize']);
21
21
  t.is(stdout.split("\n")[0], 'foobar');
22
22
  });
23
23
 
24
24
  test('preserve-leading-underscore', async t => {
25
- const {stdout} = await execa('./cli.js', ['_foo_bar', '--preserve-leading-underscore']);
25
+ const { stdout } = await execa('./cli.js', ['_foo_bar', '--preserve-leading-underscore']);
26
26
  t.is(stdout.split("\n")[0], '_foo-bar');
27
27
  });
28
+
29
+ test('parentheses', async t => {
30
+ const { stdout } = await execa('./cli.js', ['HSVDetector: a heterogeneous semantic graph-based method for smart contract vulnerability detection (Zhu et al., 2025)']);
31
+ t.is(stdout.split("\n")[0], 'hsv-detector-a-heterogeneous-semantic-graph-based-method-for-smart-contract-vulnerability-detection-zhu-et-al-2025');
32
+ });
33
+
34
+ test('colons and parentheses with no-lowercase', async t => {
35
+ const { stdout } = await execa('./cli.js', ['Paper Title: Some Research (Author et al., 2024)', '--no-lowercase']);
36
+ t.is(stdout.split("\n")[0], 'Paper-Title-Some-Research-Author-et-al-2024');
37
+ });
38
+
39
+ test('multiple special characters', async t => {
40
+ const { stdout } = await execa('./cli.js', ['Hello@World#Test$2024!']);
41
+ t.is(stdout.split("\n")[0], 'hello-world-test-2024');
42
+ });
43
+
44
+ test('brackets and braces', async t => {
45
+ const { stdout } = await execa('./cli.js', ['Array[0] and Object{key}']);
46
+ t.is(stdout.split("\n")[0], 'array-0-and-object-key');
47
+ });
48
+
49
+ test('quotes', async t => {
50
+ const { stdout } = await execa('./cli.js', ['She said "hello" and \'goodbye\'']);
51
+ t.is(stdout.split("\n")[0], 'she-said-hello-and-goodbye');
52
+ });
53
+
54
+ test('ampersands and pipes', async t => {
55
+ const { stdout } = await execa('./cli.js', ['A & B | C']);
56
+ t.is(stdout.split("\n")[0], 'a-and-b-c');
57
+ });
58
+
59
+ test('math symbols', async t => {
60
+ const { stdout } = await execa('./cli.js', ['2 + 2 = 4, 3 * 3 = 9']);
61
+ t.is(stdout.split("\n")[0], '2-2-4-3-3-9');
62
+ });
63
+
64
+ test('percentage and currency', async t => {
65
+ const { stdout } = await execa('./cli.js', ['$100 is 50% off']);
66
+ t.is(stdout.split("\n")[0], '100-is-50-off');
67
+ });
68
+
69
+ test('slashes', async t => {
70
+ const { stdout } = await execa('./cli.js', ['path/to/file.txt']);
71
+ t.is(stdout.split("\n")[0], 'path-to-file-txt');
72
+ });
73
+
74
+ test('multiple spaces and tabs', async t => {
75
+ const { stdout } = await execa('./cli.js', ['Multiple Spaces Here']);
76
+ t.is(stdout.split("\n")[0], 'multiple-spaces-here');
77
+ });
78
+
79
+ test('emoji', async t => {
80
+ const { stdout } = await execa('./cli.js', ['Hello 👋 World 🌍']);
81
+ t.is(stdout.split("\n")[0], 'hello-world');
82
+ });
83
+
84
+ test('leading and trailing spaces', async t => {
85
+ const { stdout } = await execa('./cli.js', [' Trim Me ']);
86
+ t.is(stdout.split("\n")[0], 'trim-me');
87
+ });
88
+
89
+ test('only special characters', async t => {
90
+ const { stdout } = await execa('./cli.js', ['@#$%^&*()']);
91
+ t.is(stdout.split("\n")[0], 'and');
92
+ });
93
+
94
+ test('numbers only', async t => {
95
+ const { stdout } = await execa('./cli.js', ['123456789']);
96
+ t.is(stdout.split("\n")[0], '123456789');
97
+ });
98
+
99
+ test('mixed case with numbers', async t => {
100
+ const { stdout } = await execa('./cli.js', ['iPhone15Pro', '--no-decamelize']);
101
+ t.is(stdout.split("\n")[0], 'iphone15pro');
102
+ });
103
+
104
+ test('newlines', async t => {
105
+ const { stdout } = await execa('./cli.js', ['Line 1\nLine 2\nLine 3']);
106
+ t.is(stdout.split("\n")[0], 'line-1-line-2-line-3');
107
+ });
108
+
109
+ test('tabs', async t => {
110
+ const { stdout } = await execa('./cli.js', ['Column\tA\tColumn\tB']);
111
+ t.is(stdout.split("\n")[0], 'column-a-column-b');
112
+ });
113
+
114
+ test('carriage returns', async t => {
115
+ const { stdout } = await execa('./cli.js', ['Carriage\rReturn\rTest']);
116
+ t.is(stdout.split("\n")[0], 'carriage-return-test');
117
+ });
118
+
119
+ test('mixed whitespace characters', async t => {
120
+ const { stdout } = await execa('./cli.js', ['Mix\n\tOf \rWhitespace']);
121
+ t.is(stdout.split("\n")[0], 'mix-of-whitespace');
122
+ });