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.
- package/README.md +13 -0
- package/package.json +2 -2
- 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
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
|
+
});
|