digital-conversion 0.0.0-stage → 1.0.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/LICENSE +15 -0
- package/README.md +207 -2
- package/index.js +62 -0
- package/package.json +28 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,208 @@
|
|
|
1
|
-
#
|
|
1
|
+
# digital-conversion
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/digital-conversion)
|
|
4
|
+
[](https://www.npmjs.com/package/digital-conversion)
|
|
5
|
+
[](https://www.npmjs.com/package/digital-conversion)
|
|
6
|
+
|
|
7
|
+
一個零依賴的輕量字串與數字工具組,提供反轉字串、迴文判斷、字首大寫、千分位格式化、隨機整數與數值限制等功能。
|
|
8
|
+
|
|
9
|
+
- 零依賴、體積小(未壓縮約 4.4 kB)
|
|
10
|
+
- 同時支援 CommonJS 與 ES Modules
|
|
11
|
+
- 支援 Unicode(包含中文)
|
|
12
|
+
- 完整的參數驗證與單元測試
|
|
13
|
+
|
|
14
|
+
## 安裝
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install digital-conversion
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
需求:Node.js 18 以上。
|
|
21
|
+
|
|
22
|
+
## 快速開始
|
|
23
|
+
|
|
24
|
+
### CommonJS
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
const {
|
|
28
|
+
reverseString,
|
|
29
|
+
isPalindrome,
|
|
30
|
+
capitalizeWords,
|
|
31
|
+
formatThousands,
|
|
32
|
+
randomInt,
|
|
33
|
+
clamp,
|
|
34
|
+
} = require('digital-conversion');
|
|
35
|
+
|
|
36
|
+
reverseString('hello'); // 'olleh'
|
|
37
|
+
isPalindrome('A man, a plan, a canal: Panama'); // true
|
|
38
|
+
capitalizeWords('hello world'); // 'Hello World'
|
|
39
|
+
formatThousands(1234567); // '1,234,567'
|
|
40
|
+
randomInt(1, 6); // 1 到 6 之間的整數(含頭尾)
|
|
41
|
+
clamp(42, 0, 10); // 10
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### ES Modules
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
import { reverseString, formatThousands } from 'digital-conversion';
|
|
48
|
+
|
|
49
|
+
reverseString('你好'); // '好你'
|
|
50
|
+
formatThousands(-9876543); // '-9,876,543'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
| 函式 | 說明 | 回傳 |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| [`reverseString(text)`](#reversestringtext) | 反轉字串(支援 Unicode) | `string` |
|
|
58
|
+
| [`isPalindrome(text)`](#ispalindrometext) | 判斷是否為迴文,忽略大小寫、空白與標點 | `boolean` |
|
|
59
|
+
| [`capitalizeWords(text)`](#capitalizewordstext) | 將每個單字字首大寫、其餘小寫 | `string` |
|
|
60
|
+
| [`formatThousands(value)`](#formatthousandsvalue) | 將數字加上千分位逗號 | `string` |
|
|
61
|
+
| [`randomInt(min, max)`](#randomintmin-max) | 產生含頭尾範圍的隨機整數 | `number` |
|
|
62
|
+
| [`clamp(value, min, max)`](#clampvalue-min-max) | 將數值限制在指定範圍內 | `number` |
|
|
63
|
+
|
|
64
|
+
### `reverseString(text)`
|
|
65
|
+
|
|
66
|
+
反轉字串,使用展開運算子逐字元處理,因此不會破壞 Unicode 字元。
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
reverseString('hello'); // 'olleh'
|
|
70
|
+
reverseString('你好'); // '好你'
|
|
71
|
+
reverseString(''); // ''
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- `text` `{string}`:要反轉的字串
|
|
75
|
+
- 回傳 `{string}`:反轉後的字串
|
|
76
|
+
- 拋出 `{TypeError}`:當 `text` 不是字串
|
|
77
|
+
|
|
78
|
+
### `isPalindrome(text)`
|
|
79
|
+
|
|
80
|
+
判斷是否為迴文。比較前會忽略大小寫、空白、標點符號,並保留英數字與中文字。
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
isPalindrome('racecar'); // true
|
|
84
|
+
isPalindrome('A man, a plan, a canal: Panama'); // true
|
|
85
|
+
isPalindrome('hello'); // false
|
|
86
|
+
isPalindrome(''); // true
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- `text` `{string}`:要檢查的字串
|
|
90
|
+
- 回傳 `{boolean}`:是迴文回傳 `true`,否則 `false`
|
|
91
|
+
- 拋出 `{TypeError}`:當 `text` 不是字串
|
|
92
|
+
|
|
93
|
+
### `capitalizeWords(text)`
|
|
94
|
+
|
|
95
|
+
將每個以空白分隔的單字字首轉為大寫、其餘字母轉為小寫,原始空白與斷行會保留。
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
capitalizeWords('hello world'); // 'Hello World'
|
|
99
|
+
capitalizeWords('hELLO wORLD'); // 'Hello World'
|
|
100
|
+
capitalizeWords(' multiple spaces '); // ' Multiple Spaces '
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- `text` `{string}`:要轉換的字串
|
|
104
|
+
- 回傳 `{string}`:轉換後的字串
|
|
105
|
+
- 拋出 `{TypeError}`:當 `text` 不是字串
|
|
106
|
+
|
|
107
|
+
### `formatThousands(value)`
|
|
108
|
+
|
|
109
|
+
將數字加上千分位逗號,支援負數與小數。
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
formatThousands(999); // '999'
|
|
113
|
+
formatThousands(1000); // '1,000'
|
|
114
|
+
formatThousands(1234567); // '1,234,567'
|
|
115
|
+
formatThousands(-9876543.21); // '-9,876,543.21'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- `value` `{number}`:要格式化的有限數值
|
|
119
|
+
- 回傳 `{string}`:加上千分位的字串
|
|
120
|
+
- 拋出 `{TypeError}`:當 `value` 不是有限數字(例如 `NaN`、`Infinity`、字串)
|
|
121
|
+
|
|
122
|
+
### `randomInt(min, max)`
|
|
123
|
+
|
|
124
|
+
產生介於 `min` 與 `max` 之間(含頭尾)的隨機整數。
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
randomInt(1, 6); // 1、2、3、4、5 或 6
|
|
128
|
+
randomInt(5, 5); // 5
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- `min` `{number}`:範圍下限(整數)
|
|
132
|
+
- `max` `{number}`:範圍上限(整數)
|
|
133
|
+
- 回傳 `{number}`:範圍內的隨機整數
|
|
134
|
+
- 拋出 `{TypeError}`:當 `min` 或 `max` 不是整數
|
|
135
|
+
- 拋出 `{RangeError}`:當 `min` 大於 `max`
|
|
136
|
+
|
|
137
|
+
### `clamp(value, min, max)`
|
|
138
|
+
|
|
139
|
+
將數值限制在指定範圍內:小於下限回傳下限,大於上限回傳上限。
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
clamp(5, 0, 10); // 5
|
|
143
|
+
clamp(-3, 0, 10); // 0
|
|
144
|
+
clamp(42, 0, 10); // 10
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- `value` `{number}`:要限制的有限數值
|
|
148
|
+
- `min` `{number}`:範圍下限
|
|
149
|
+
- `max` `{number}`:範圍上限
|
|
150
|
+
- 回傳 `{number}`:限制後的數值
|
|
151
|
+
- 拋出 `{TypeError}`:當參數不是有限數字
|
|
152
|
+
- 拋出 `{RangeError}`:當 `min` 大於 `max`
|
|
153
|
+
|
|
154
|
+
## 錯誤處理
|
|
155
|
+
|
|
156
|
+
所有函式都會驗證參數型別,錯誤會以標準的 `TypeError` 或 `RangeError` 拋出,方便搭配 `try/catch` 使用:
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
const { formatThousands, randomInt } = require('digital-conversion');
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
formatThousands('1000');
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error(error.name); // 'TypeError'
|
|
165
|
+
console.error(error.message); // 'value must be a finite number'
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
randomInt(10, 1);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(error.name); // 'RangeError'
|
|
172
|
+
console.error(error.message); // 'min must be less than or equal to max'
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 開發
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# 安裝專案(本套件無執行期依賴)
|
|
180
|
+
npm install
|
|
181
|
+
|
|
182
|
+
# 執行單元測試(使用 Node.js 內建 test runner)
|
|
183
|
+
npm test
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
專案結構:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
digital-conversion/
|
|
190
|
+
├── index.js # 套件原始碼
|
|
191
|
+
├── test/
|
|
192
|
+
│ └── index.test.js # 單元測試
|
|
193
|
+
├── README.md
|
|
194
|
+
├── LICENSE
|
|
195
|
+
└── package.json
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## 版本規則
|
|
199
|
+
|
|
200
|
+
本套件遵循 [Semantic Versioning](https://semver.org/):
|
|
201
|
+
|
|
202
|
+
- 修正錯誤:`patch`(例如 `1.0.0` → `1.0.1`)
|
|
203
|
+
- 向下相容的新功能:`minor`(例如 `1.0.0` → `1.1.0`)
|
|
204
|
+
- 不相容的變更:`major`(例如 `1.0.0` → `2.0.0`)
|
|
205
|
+
|
|
206
|
+
## 授權
|
|
207
|
+
|
|
208
|
+
[ISC](LICENSE)
|
package/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function assertString(value, name = 'value') {
|
|
4
|
+
if (typeof value !== 'string') {
|
|
5
|
+
throw new TypeError(`${name} must be a string`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function reverseString(text) {
|
|
10
|
+
assertString(text, 'text');
|
|
11
|
+
return [...text].reverse().join('');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isPalindrome(text) {
|
|
15
|
+
assertString(text, 'text');
|
|
16
|
+
const normalized = text.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]/g, '');
|
|
17
|
+
return normalized === [...normalized].reverse().join('');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function capitalizeWords(text) {
|
|
21
|
+
assertString(text, 'text');
|
|
22
|
+
return text.replace(/\S+/g, (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function formatThousands(value) {
|
|
26
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
27
|
+
throw new TypeError('value must be a finite number');
|
|
28
|
+
}
|
|
29
|
+
return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function randomInt(min, max) {
|
|
33
|
+
if (!Number.isInteger(min) || !Number.isInteger(max)) {
|
|
34
|
+
throw new TypeError('min and max must be integers');
|
|
35
|
+
}
|
|
36
|
+
if (min > max) {
|
|
37
|
+
throw new RangeError('min must be less than or equal to max');
|
|
38
|
+
}
|
|
39
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function clamp(value, min, max) {
|
|
43
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
44
|
+
throw new TypeError('value must be a finite number');
|
|
45
|
+
}
|
|
46
|
+
if (typeof min !== 'number' || typeof max !== 'number') {
|
|
47
|
+
throw new TypeError('min and max must be numbers');
|
|
48
|
+
}
|
|
49
|
+
if (min > max) {
|
|
50
|
+
throw new RangeError('min must be less than or equal to max');
|
|
51
|
+
}
|
|
52
|
+
return Math.min(Math.max(value, min), max);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = {
|
|
56
|
+
reverseString,
|
|
57
|
+
isPalindrome,
|
|
58
|
+
capitalizeWords,
|
|
59
|
+
formatThousands,
|
|
60
|
+
randomInt,
|
|
61
|
+
clamp,
|
|
62
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "digital-conversion",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight collection of string and number utilities: reverse, palindrome check, capitalize, thousands separator, random integer and clamp.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"string",
|
|
16
|
+
"number",
|
|
17
|
+
"utilities",
|
|
18
|
+
"utils",
|
|
19
|
+
"palindrome",
|
|
20
|
+
"format",
|
|
21
|
+
"random",
|
|
22
|
+
"clamp"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "node --test"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
}
|
|
30
|
+
}
|