taiwan-validator 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 +21 -0
- package/README.en.md +214 -0
- package/README.md +214 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +128 -0
- package/src/index.ts +26 -0
- package/src/types.ts +22 -0
- package/src/validators/business-number.test.ts +63 -0
- package/src/validators/business-number.ts +59 -0
- package/src/validators/citizen-certificate.test.ts +73 -0
- package/src/validators/citizen-certificate.ts +41 -0
- package/src/validators/einvoice-donation-code.test.ts +78 -0
- package/src/validators/einvoice-donation-code.ts +42 -0
- package/src/validators/einvoice-mobile-barcode.test.ts +67 -0
- package/src/validators/einvoice-mobile-barcode.ts +45 -0
- package/src/validators/mobile-phone.test.ts +67 -0
- package/src/validators/mobile-phone.ts +41 -0
- package/src/validators/national-id.test.ts +99 -0
- package/src/validators/national-id.ts +181 -0
- package/src/validators/resident-certificate.test.ts +129 -0
- package/src/validators/resident-certificate.ts +181 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Gary Lai
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Taiwan Validator
|
|
2
|
+
|
|
3
|
+
A comprehensive TypeScript validator for Taiwan identification numbers and codes.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/imgarylai/taiwan-validator/actions/workflows/test.yml)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
[繁體中文](README.md)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- ✅ National ID validation (身分證字號) - Both old and new formats
|
|
13
|
+
- ✅ Business Uniform Number validation (統一編號)
|
|
14
|
+
- ✅ Resident Certificate validation (居留證號) - Both old and new formats
|
|
15
|
+
- ✅ Mobile Phone Number validation (手機號碼)
|
|
16
|
+
- ✅ Citizen Digital Certificate validation (自然人憑證)
|
|
17
|
+
- ✅ e-Invoice Mobile Barcode validation (電子發票手機條碼)
|
|
18
|
+
- ✅ e-Invoice Donation Code validation (電子發票捐贈碼)
|
|
19
|
+
- 📘 Full TypeScript support with type definitions
|
|
20
|
+
- 🧪 Thoroughly tested with 100% coverage
|
|
21
|
+
- 📦 Tree-shakeable ESM and CommonJS support
|
|
22
|
+
- 🚀 Zero dependencies
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install taiwan-validator
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import {
|
|
34
|
+
validateNationalId,
|
|
35
|
+
validateBusinessNumber,
|
|
36
|
+
validateResidentCertificate,
|
|
37
|
+
validateMobilePhone,
|
|
38
|
+
validateCitizenCertificate,
|
|
39
|
+
validateEInvoiceMobileBarcode,
|
|
40
|
+
validateEInvoiceDonationCode,
|
|
41
|
+
} from "taiwan-validator";
|
|
42
|
+
|
|
43
|
+
// National ID (身分證字號)
|
|
44
|
+
validateNationalId("A123456789"); // { isValid: true }
|
|
45
|
+
validateNationalId("AA23456786"); // { isValid: true } - New format
|
|
46
|
+
|
|
47
|
+
// Business Number (統一編號)
|
|
48
|
+
validateBusinessNumber("12345676"); // { isValid: true }
|
|
49
|
+
|
|
50
|
+
// Resident Certificate (居留證號)
|
|
51
|
+
validateResidentCertificate("A823456783"); // { isValid: true } - Old format
|
|
52
|
+
validateResidentCertificate("AA23456786"); // { isValid: true } - New format
|
|
53
|
+
|
|
54
|
+
// Mobile Phone (手機號碼)
|
|
55
|
+
validateMobilePhone("0912345678"); // { isValid: true }
|
|
56
|
+
validateMobilePhone("0912-345-678"); // { isValid: true } - With separators
|
|
57
|
+
|
|
58
|
+
// Citizen Digital Certificate (自然人憑證)
|
|
59
|
+
validateCitizenCertificate("AB12345678901234"); // { isValid: true }
|
|
60
|
+
|
|
61
|
+
// e-Invoice Mobile Barcode (電子發票手機條碼)
|
|
62
|
+
validateEInvoiceMobileBarcode("/ABCD123"); // { isValid: true }
|
|
63
|
+
|
|
64
|
+
// e-Invoice Donation Code (電子發票捐贈碼)
|
|
65
|
+
validateEInvoiceDonationCode("12345"); // { isValid: true }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## API Documentation
|
|
69
|
+
|
|
70
|
+
### `validateNationalId(id: string, format?: 'old' | 'new'): ValidationResult`
|
|
71
|
+
|
|
72
|
+
Validates Taiwan National ID (身分證字號).
|
|
73
|
+
|
|
74
|
+
- **Old format**: 1 letter + 9 digits (e.g., `A123456789`)
|
|
75
|
+
- **New format**: 2 letters + 8 digits (e.g., `AA23456786`)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
validateNationalId("A123456789"); // Auto-detect format
|
|
79
|
+
validateNationalId("A123456789", "old"); // Explicitly check old format
|
|
80
|
+
validateNationalId("AA23456786", "new"); // Explicitly check new format
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `validateBusinessNumber(number: string): ValidationResult`
|
|
84
|
+
|
|
85
|
+
Validates Taiwan Business Uniform Number (統一編號).
|
|
86
|
+
|
|
87
|
+
- **Format**: 8 digits with checksum validation
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
validateBusinessNumber("12345676");
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `validateResidentCertificate(id: string, format?: 'old' | 'new'): ValidationResult`
|
|
94
|
+
|
|
95
|
+
Validates Taiwan Resident Certificate (居留證號).
|
|
96
|
+
|
|
97
|
+
- **Old format**: 1 letter (A-D) + 9 digits starting with 8 or 9
|
|
98
|
+
- **New format**: 2 letters + 8 digits
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
validateResidentCertificate("A823456783"); // Auto-detect format
|
|
102
|
+
validateResidentCertificate("A823456783", "old"); // Old format
|
|
103
|
+
validateResidentCertificate("AA23456786", "new"); // New format
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `validateMobilePhone(phone: string): ValidationResult`
|
|
107
|
+
|
|
108
|
+
Validates Taiwan mobile phone number (手機號碼).
|
|
109
|
+
|
|
110
|
+
- **Format**: 10 digits starting with 09
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
validateMobilePhone("0912345678");
|
|
114
|
+
validateMobilePhone("0912-345-678"); // Accepts separators
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `validateCitizenCertificate(certNumber: string): ValidationResult`
|
|
118
|
+
|
|
119
|
+
Validates Taiwan Citizen Digital Certificate Number (自然人憑證).
|
|
120
|
+
|
|
121
|
+
- **Format**: 2 uppercase letters + 14 digits
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
validateCitizenCertificate("AB12345678901234");
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `validateEInvoiceMobileBarcode(barcode: string): ValidationResult`
|
|
128
|
+
|
|
129
|
+
Validates Taiwan e-Invoice Mobile Barcode (電子發票手機條碼).
|
|
130
|
+
|
|
131
|
+
- **Format**: `/` + 7 characters (A-Z, 0-9, +, -, .)
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
validateEInvoiceMobileBarcode("/ABCD123");
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `validateEInvoiceDonationCode(code: string): ValidationResult`
|
|
138
|
+
|
|
139
|
+
Validates Taiwan e-Invoice Donation Code (電子發票捐贈碼).
|
|
140
|
+
|
|
141
|
+
- **Format**: 3-7 digits
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
validateEInvoiceDonationCode("12345");
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Return Type
|
|
148
|
+
|
|
149
|
+
All validation functions return a `ValidationResult` object:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
interface ValidationResult {
|
|
153
|
+
isValid: boolean;
|
|
154
|
+
message?: string; // Error message when isValid is false
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
### Setup
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Clone the repository
|
|
164
|
+
git clone https://github.com/imgarylai/taiwan-validator.git
|
|
165
|
+
cd taiwan-validator
|
|
166
|
+
|
|
167
|
+
# Install dependencies
|
|
168
|
+
npm install
|
|
169
|
+
|
|
170
|
+
# Run tests
|
|
171
|
+
npm test
|
|
172
|
+
|
|
173
|
+
# Run tests with coverage
|
|
174
|
+
npm run test:coverage
|
|
175
|
+
|
|
176
|
+
# Build the package
|
|
177
|
+
npm run build
|
|
178
|
+
|
|
179
|
+
# Development mode (watch)
|
|
180
|
+
npm run dev
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Available Scripts
|
|
184
|
+
|
|
185
|
+
- `npm run build` - Build the package with tsup
|
|
186
|
+
- `npm run dev` - Watch mode for development
|
|
187
|
+
- `npm test` - Run tests
|
|
188
|
+
- `npm run test:coverage` - Run tests with coverage
|
|
189
|
+
- `npm run lint` - Lint the code
|
|
190
|
+
- `npm run type-check` - Check types
|
|
191
|
+
- `npm run docs` - Generate documentation
|
|
192
|
+
- `npm run clean` - Clean build outputs
|
|
193
|
+
|
|
194
|
+
## Contributing
|
|
195
|
+
|
|
196
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
197
|
+
|
|
198
|
+
1. Fork the repository
|
|
199
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
200
|
+
3. Commit your changes using conventional commits (`git commit -m 'feat: add amazing feature'`)
|
|
201
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
202
|
+
5. Open a Pull Request
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
207
|
+
|
|
208
|
+
## Author
|
|
209
|
+
|
|
210
|
+
Gary Lai - [@imgarylai](https://github.com/imgarylai)
|
|
211
|
+
|
|
212
|
+
## Acknowledgments
|
|
213
|
+
|
|
214
|
+
This package implements the official validation algorithms for Taiwan identification numbers and codes.
|
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Taiwan Validator
|
|
2
|
+
|
|
3
|
+
一個完整的台灣身分證件與代碼驗證 TypeScript 套件。
|
|
4
|
+
|
|
5
|
+
[](https://github.com/imgarylai/taiwan-validator/actions/workflows/test.yml)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
[English](README.en.md)
|
|
9
|
+
|
|
10
|
+
## 功能特色
|
|
11
|
+
|
|
12
|
+
- ✅ 身分證字號驗證 - 支援新舊格式
|
|
13
|
+
- ✅ 統一編號驗證
|
|
14
|
+
- ✅ 居留證號驗證 - 支援新舊格式
|
|
15
|
+
- ✅ 手機號碼驗證
|
|
16
|
+
- ✅ 自然人憑證驗證
|
|
17
|
+
- ✅ 電子發票手機條碼驗證
|
|
18
|
+
- ✅ 電子發票捐贈碼驗證
|
|
19
|
+
- 📘 完整的 TypeScript 型別定義
|
|
20
|
+
- 🧪 完整測試覆蓋率
|
|
21
|
+
- 📦 支援 ESM 和 CommonJS 且可 Tree-shaking
|
|
22
|
+
- 🚀 零依賴
|
|
23
|
+
|
|
24
|
+
## 安裝
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install taiwan-validator
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 使用方式
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import {
|
|
34
|
+
validateNationalId,
|
|
35
|
+
validateBusinessNumber,
|
|
36
|
+
validateResidentCertificate,
|
|
37
|
+
validateMobilePhone,
|
|
38
|
+
validateCitizenCertificate,
|
|
39
|
+
validateEInvoiceMobileBarcode,
|
|
40
|
+
validateEInvoiceDonationCode,
|
|
41
|
+
} from "taiwan-validator";
|
|
42
|
+
|
|
43
|
+
// 身分證字號
|
|
44
|
+
validateNationalId("A123456789"); // { isValid: true }
|
|
45
|
+
validateNationalId("AA23456786"); // { isValid: true } - 新式格式
|
|
46
|
+
|
|
47
|
+
// 統一編號
|
|
48
|
+
validateBusinessNumber("12345676"); // { isValid: true }
|
|
49
|
+
|
|
50
|
+
// 居留證號
|
|
51
|
+
validateResidentCertificate("A823456783"); // { isValid: true } - 舊式
|
|
52
|
+
validateResidentCertificate("AA23456786"); // { isValid: true } - 新式
|
|
53
|
+
|
|
54
|
+
// 手機號碼
|
|
55
|
+
validateMobilePhone("0912345678"); // { isValid: true }
|
|
56
|
+
validateMobilePhone("0912-345-678"); // { isValid: true } - 含分隔符號
|
|
57
|
+
|
|
58
|
+
// 自然人憑證
|
|
59
|
+
validateCitizenCertificate("AB12345678901234"); // { isValid: true }
|
|
60
|
+
|
|
61
|
+
// 電子發票手機條碼
|
|
62
|
+
validateEInvoiceMobileBarcode("/ABCD123"); // { isValid: true }
|
|
63
|
+
|
|
64
|
+
// 電子發票捐贈碼
|
|
65
|
+
validateEInvoiceDonationCode("12345"); // { isValid: true }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## API 文件
|
|
69
|
+
|
|
70
|
+
### `validateNationalId(id: string, format?: 'old' | 'new'): ValidationResult`
|
|
71
|
+
|
|
72
|
+
驗證台灣身分證字號。
|
|
73
|
+
|
|
74
|
+
- **舊式格式**:1 個英文字母 + 9 個數字(例如:`A123456789`)
|
|
75
|
+
- **新式格式**:2 個英文字母 + 8 個數字(例如:`AA23456786`)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
validateNationalId("A123456789"); // 自動偵測格式
|
|
79
|
+
validateNationalId("A123456789", "old"); // 明確指定舊式格式
|
|
80
|
+
validateNationalId("AA23456786", "new"); // 明確指定新式格式
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `validateBusinessNumber(number: string): ValidationResult`
|
|
84
|
+
|
|
85
|
+
驗證台灣統一編號。
|
|
86
|
+
|
|
87
|
+
- **格式**:8 位數字,含檢查碼驗證
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
validateBusinessNumber("12345676");
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `validateResidentCertificate(id: string, format?: 'old' | 'new'): ValidationResult`
|
|
94
|
+
|
|
95
|
+
驗證台灣居留證號。
|
|
96
|
+
|
|
97
|
+
- **舊式格式**:1 個英文字母(A-D)+ 9 個數字(第二位為 8 或 9)
|
|
98
|
+
- **新式格式**:2 個英文字母 + 8 個數字
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
validateResidentCertificate("A823456783"); // 自動偵測格式
|
|
102
|
+
validateResidentCertificate("A823456783", "old"); // 舊式格式
|
|
103
|
+
validateResidentCertificate("AA23456786", "new"); // 新式格式
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `validateMobilePhone(phone: string): ValidationResult`
|
|
107
|
+
|
|
108
|
+
驗證台灣手機號碼。
|
|
109
|
+
|
|
110
|
+
- **格式**:10 位數字,以 09 開頭
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
validateMobilePhone("0912345678");
|
|
114
|
+
validateMobilePhone("0912-345-678"); // 接受分隔符號
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `validateCitizenCertificate(certNumber: string): ValidationResult`
|
|
118
|
+
|
|
119
|
+
驗證台灣自然人憑證號碼。
|
|
120
|
+
|
|
121
|
+
- **格式**:2 個大寫英文字母 + 14 位數字
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
validateCitizenCertificate("AB12345678901234");
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `validateEInvoiceMobileBarcode(barcode: string): ValidationResult`
|
|
128
|
+
|
|
129
|
+
驗證台灣電子發票手機條碼。
|
|
130
|
+
|
|
131
|
+
- **格式**:`/` + 7 個字元(A-Z、0-9、+、-、.)
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
validateEInvoiceMobileBarcode("/ABCD123");
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `validateEInvoiceDonationCode(code: string): ValidationResult`
|
|
138
|
+
|
|
139
|
+
驗證台灣電子發票捐贈碼。
|
|
140
|
+
|
|
141
|
+
- **格式**:3-7 位數字
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
validateEInvoiceDonationCode("12345");
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 回傳型別
|
|
148
|
+
|
|
149
|
+
所有驗證函式都會回傳 `ValidationResult` 物件:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
interface ValidationResult {
|
|
153
|
+
isValid: boolean;
|
|
154
|
+
message?: string; // 當 isValid 為 false 時的錯誤訊息
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 開發
|
|
159
|
+
|
|
160
|
+
### 設定
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# 複製專案
|
|
164
|
+
git clone https://github.com/imgarylai/taiwan-validator.git
|
|
165
|
+
cd taiwan-validator
|
|
166
|
+
|
|
167
|
+
# 安裝相依套件
|
|
168
|
+
npm install
|
|
169
|
+
|
|
170
|
+
# 執行測試
|
|
171
|
+
npm test
|
|
172
|
+
|
|
173
|
+
# 執行測試並產生覆蓋率報告
|
|
174
|
+
npm run test:coverage
|
|
175
|
+
|
|
176
|
+
# 建置套件
|
|
177
|
+
npm run build
|
|
178
|
+
|
|
179
|
+
# 開發模式(監看)
|
|
180
|
+
npm run dev
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 可用指令
|
|
184
|
+
|
|
185
|
+
- `npm run build` - 使用 tsup 建置套件
|
|
186
|
+
- `npm run dev` - 開發模式(監看)
|
|
187
|
+
- `npm test` - 執行測試
|
|
188
|
+
- `npm run test:coverage` - 執行測試並產生覆蓋率報告
|
|
189
|
+
- `npm run lint` - 程式碼檢查
|
|
190
|
+
- `npm run type-check` - 型別檢查
|
|
191
|
+
- `npm run docs` - 產生文件
|
|
192
|
+
- `npm run clean` - 清除建置輸出
|
|
193
|
+
|
|
194
|
+
## 貢獻
|
|
195
|
+
|
|
196
|
+
歡迎貢獻!請隨時提交 Pull Request。
|
|
197
|
+
|
|
198
|
+
1. Fork 此專案
|
|
199
|
+
2. 建立你的功能分支 (`git checkout -b feature/amazing-feature`)
|
|
200
|
+
3. 使用 conventional commits 提交你的變更 (`git commit -m 'feat: add amazing feature'`)
|
|
201
|
+
4. 推送到分支 (`git push origin feature/amazing-feature`)
|
|
202
|
+
5. 開啟一個 Pull Request
|
|
203
|
+
|
|
204
|
+
## 授權
|
|
205
|
+
|
|
206
|
+
本專案使用 MIT 授權 - 詳見 [LICENSE](LICENSE) 檔案。
|
|
207
|
+
|
|
208
|
+
## 作者
|
|
209
|
+
|
|
210
|
+
Gary Lai - [@imgarylai](https://github.com/imgarylai)
|
|
211
|
+
|
|
212
|
+
## 致謝
|
|
213
|
+
|
|
214
|
+
本套件實作了台灣官方的身分證件與代碼驗證演算法。
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var V={A:10,B:11,C:12,D:13,E:14,F:15,G:16,H:17,I:34,J:18,K:19,L:20,M:21,N:22,O:35,P:23,Q:24,R:25,S:26,T:27,U:28,V:29,W:32,X:30,Y:31,Z:33};function R(t){if(!/^[A-Z][12]\d{8}$/.test(t))return false;let s=t[0],i=t.slice(1),r=V[s],e=Math.floor(r/10),a=r%10,o=[1,9,8,7,6,5,4,3,2,1,1];return [e,a,...i.split("").map(Number)].reduce((d,u,f)=>d+u*o[f],0)%10===0}function v(t){if(!/^[A-Z]{2}\d{8}$/.test(t))return false;let s=t[0],i=t[1],r=t.slice(2),e=V[s],a=V[i],o=Math.floor(e/10),l=e%10,c=Math.floor(a/10),d=a%10,u=[1,9,8,7,6,5,4,3,2,1,1,1];return [o,l,c,d,...r.split("").map(Number)].reduce((m,p,g)=>m+p*u[g],0)%10===0}function I(t){return /^[A-Z][12]\d{8}$/.test(t)?"old":/^[A-Z]{2}\d{8}$/.test(t)?"new":null}function x(t,n){if(!t||typeof t!="string")return {isValid:false,message:"\u8EAB\u5206\u8B49\u5B57\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let s=t.trim().toUpperCase();if(n==="old"){let e=R(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u820A\u5F0F\u8EAB\u5206\u8B49\u5B57\u865F"}}if(n==="new"){let e=v(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u65B0\u5F0F\u8EAB\u5206\u8B49\u5B57\u865F"}}let i=I(s);if(!i)return {isValid:false,message:"\u7121\u6548\u7684\u8EAB\u5206\u8B49\u5B57\u865F\u683C\u5F0F"};let r=i==="old"?R(s):v(s);return {isValid:r,message:r?void 0:`\u7121\u6548\u7684${i==="old"?"\u820A\u5F0F":"\u65B0\u5F0F"}\u8EAB\u5206\u8B49\u5B57\u865F`}}function A(t){if(!t||typeof t!="string")return {isValid:false,message:"\u7D71\u4E00\u7DE8\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim();if(!/^\d{8}$/.test(n))return {isValid:false,message:"\u7D71\u4E00\u7DE8\u865F\u5FC5\u9808\u70BA8\u4F4D\u6578\u5B57"};let i=n.split("").map(Number),r=[1,2,1,2,1,2,4,1],e=0;for(let o=0;o<8;o++){let l=i[o]*r[o];l>=10&&(l=Math.floor(l/10)+l%10),e+=l;}let a=e%10===0||i[6]===7&&e%10===1;return {isValid:a,message:a?void 0:"\u7D71\u4E00\u7DE8\u865F\u6AA2\u67E5\u78BC\u932F\u8AA4"}}var y={A:10,B:11,C:12,D:13,E:14,F:15,G:16,H:17,I:34,J:18,K:19,L:20,M:21,N:22,O:35,P:23,Q:24,R:25,S:26,T:27,U:28,V:29,W:32,X:30,Y:31,Z:33};function b(t){if(!/^[A-D][89]\d{8}$/.test(t))return false;let s=t[0],i=t.slice(1),r=y[s],e=Math.floor(r/10),a=r%10,o=[1,9,8,7,6,5,4,3,2,1,1];return [e,a,...i.split("").map(Number)].reduce((d,u,f)=>d+u*o[f],0)%10===0}function C(t){if(!/^[A-Z]{2}\d{8}$/.test(t))return false;let s=t[0],i=t[1],r=t.slice(2),e=y[s],a=y[i],o=Math.floor(e/10),l=e%10,c=Math.floor(a/10),d=a%10,u=[1,9,8,7,6,5,4,3,2,1,1,1];return [o,l,c,d,...r.split("").map(Number)].reduce((m,p,g)=>m+p*u[g],0)%10===0}function M(t){return /^[A-D][89]\d{8}$/.test(t)?"old":/^[A-Z]{2}\d{8}$/.test(t)?"new":null}function $(t,n){if(!t||typeof t!="string")return {isValid:false,message:"\u5C45\u7559\u8B49\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let s=t.trim().toUpperCase();if(n==="old"){let e=b(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u820A\u5F0F\u5C45\u7559\u8B49\u865F"}}if(n==="new"){let e=C(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u65B0\u5F0F\u5C45\u7559\u8B49\u865F"}}let i=M(s);if(!i)return {isValid:false,message:"\u7121\u6548\u7684\u5C45\u7559\u8B49\u865F\u683C\u5F0F"};let r=i==="old"?b(s):C(s);return {isValid:r,message:r?void 0:`\u7121\u6548\u7684${i==="old"?"\u820A\u5F0F":"\u65B0\u5F0F"}\u5C45\u7559\u8B49\u865F`}}function T(t){if(!t||typeof t!="string")return {isValid:false,message:"\u624B\u6A5F\u865F\u78BC\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim().replace(/[\s\-()]/g,"");return /^09\d{8}$/.test(n)?{isValid:true}:{isValid:false,message:"\u624B\u6A5F\u865F\u78BC\u5FC5\u9808\u4EE509\u958B\u982D\u4E14\u70BA10\u4F4D\u6578\u5B57"}}function h(t){if(!t||typeof t!="string")return {isValid:false,message:"\u81EA\u7136\u4EBA\u6191\u8B49\u7DE8\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim().toUpperCase();return /^[A-Z]{2}\d{14}$/.test(n)?{isValid:true}:{isValid:false,message:"\u81EA\u7136\u4EBA\u6191\u8B49\u7DE8\u865F\u5FC5\u9808\u70BA2\u500B\u82F1\u6587\u5B57\u6BCD\u52A0\u4E0A14\u4F4D\u6578\u5B57"}}function L(t){if(!t||typeof t!="string")return {isValid:false,message:"\u624B\u6A5F\u689D\u78BC\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim().toUpperCase();return /^\/[A-Z0-9+.-]{7}$/.test(n)?{isValid:true}:{isValid:false,message:"\u624B\u6A5F\u689D\u78BC\u5FC5\u9808\u4EE5 / \u958B\u982D\uFF0C\u5F8C\u63A57\u500B\u6709\u6548\u5B57\u5143\uFF08A-Z\u30010-9\u3001+\u3001-\u3001.\uFF09"}}function w(t){if(!t||typeof t!="string")return {isValid:false,message:"\u6350\u8D08\u78BC\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim();return /^\d{3,7}$/.test(n)?{isValid:true}:{isValid:false,message:"\u6350\u8D08\u78BC\u5FC5\u9808\u70BA3\u81F37\u4F4D\u6578\u5B57"}}exports.validateBusinessNumber=A;exports.validateCitizenCertificate=h;exports.validateEInvoiceDonationCode=w;exports.validateEInvoiceMobileBarcode=L;exports.validateMobilePhone=T;exports.validateNationalId=x;exports.validateResidentCertificate=$;//# sourceMappingURL=index.cjs.map
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validators/national-id.ts","../src/validators/business-number.ts","../src/validators/resident-certificate.ts","../src/validators/mobile-phone.ts","../src/validators/citizen-certificate.ts","../src/validators/einvoice-mobile-barcode.ts","../src/validators/einvoice-donation-code.ts"],"names":["LETTER_MAPPING","validateOldFormat","id","letter","numbers","letterValue","d1","d2","weights","acc","digit","index","validateNewFormat","firstLetter","secondLetter","firstLetterValue","secondLetterValue","d3","d4","detectFormat","validateNationalId","format","normalizedId","isValid","detectedFormat","validateBusinessNumber","number","normalized","digits","sum","i","product","validateResidentCertificate","validateMobilePhone","phone","validateCitizenCertificate","certNumber","validateEInvoiceMobileBarcode","barcode","validateEInvoiceDonationCode","code"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ValidationResult, NationalIdType } from \"../types\";\n\n/**\n * 字母對應數字表(用於身分證字號驗證)\n */\nconst LETTER_MAPPING: Record<string, number> = {\n A: 10,\n B: 11,\n C: 12,\n D: 13,\n E: 14,\n F: 15,\n G: 16,\n H: 17,\n I: 34,\n J: 18,\n K: 19,\n L: 20,\n M: 21,\n N: 22,\n O: 35,\n P: 23,\n Q: 24,\n R: 25,\n S: 26,\n T: 27,\n U: 28,\n V: 29,\n W: 32,\n X: 30,\n Y: 31,\n Z: 33,\n};\n\n/**\n * 驗證舊式身分證字號格式(1個字母 + 9個數字)\n * 格式:A123456789\n * - 第一個字元:地區代碼(字母)\n * - 第二個字元:性別(1 = 男性,2 = 女性)\n * - 最後一個字元:檢查碼\n */\nfunction validateOldFormat(id: string): boolean {\n const pattern = /^[A-Z][12]\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const letter = id[0] as string;\n const numbers = id.slice(1);\n\n const letterValue = LETTER_MAPPING[letter] as number;\n\n // 計算檢查碼\n const d1 = Math.floor(letterValue / 10);\n const d2 = letterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1];\n const digits = [d1, d2, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 驗證新式身分證字號格式(2個字母 + 8個數字)\n * 格式:AA12345678\n * - 第一個字元:地區代碼(字母)\n * - 第二個字元:性別(8 = 男性,9 = 女性)以字母表示\n * - 最後一個字元:檢查碼\n */\nfunction validateNewFormat(id: string): boolean {\n const pattern = /^[A-Z]{2}\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const firstLetter = id[0] as string;\n const secondLetter = id[1] as string;\n const numbers = id.slice(2);\n\n const firstLetterValue = LETTER_MAPPING[firstLetter] as number;\n const secondLetterValue = LETTER_MAPPING[secondLetter] as number;\n\n // 計算新式格式的檢查碼\n const d1 = Math.floor(firstLetterValue / 10);\n const d2 = firstLetterValue % 10;\n const d3 = Math.floor(secondLetterValue / 10);\n const d4 = secondLetterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 1];\n const digits = [d1, d2, d3, d4, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 偵測身分證字號格式類型\n */\nfunction detectFormat(id: string): NationalIdType | null {\n if (/^[A-Z][12]\\d{8}$/.test(id)) {\n return \"old\";\n }\n if (/^[A-Z]{2}\\d{8}$/.test(id)) {\n return \"new\";\n }\n return null;\n}\n\n/**\n * 驗證台灣身分證字號(支援新舊格式)\n * @param id - 要驗證的身分證字號\n * @param format - 可選:指定格式類型('old' 或 'new')\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateNationalId('A123456789'); // 舊式格式\n * validateNationalId('AA12345678'); // 新式格式\n * ```\n */\nexport function validateNationalId(\n id: string,\n format?: NationalIdType,\n): ValidationResult {\n if (!id || typeof id !== \"string\") {\n return {\n isValid: false,\n message: \"身分證字號必須為非空字串\",\n };\n }\n\n const normalizedId = id.trim().toUpperCase();\n\n // 如果指定了格式,只驗證該格式\n if (format === \"old\") {\n const isValid = validateOldFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的舊式身分證字號\",\n };\n }\n\n if (format === \"new\") {\n const isValid = validateNewFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的新式身分證字號\",\n };\n }\n\n // 自動偵測格式\n const detectedFormat = detectFormat(normalizedId);\n\n if (!detectedFormat) {\n return {\n isValid: false,\n message: \"無效的身分證字號格式\",\n };\n }\n\n const isValid =\n detectedFormat === \"old\"\n ? validateOldFormat(normalizedId)\n : validateNewFormat(normalizedId);\n\n return {\n isValid,\n message: isValid\n ? undefined\n : `無效的${detectedFormat === \"old\" ? \"舊式\" : \"新式\"}身分證字號`,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣營利事業統一編號\n * 格式:8位數字\n * 使用加權檢查碼演算法\n *\n * @param number - 要驗證的統一編號\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateBusinessNumber('12345678');\n * ```\n */\nexport function validateBusinessNumber(number: string): ValidationResult {\n if (!number || typeof number !== \"string\") {\n return {\n isValid: false,\n message: \"統一編號必須為非空字串\",\n };\n }\n\n const normalized = number.trim();\n\n // 檢查是否為8位數字\n const pattern = /^\\d{8}$/;\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"統一編號必須為8位數字\",\n };\n }\n\n const digits = normalized.split(\"\").map(Number);\n const weights = [1, 2, 1, 2, 1, 2, 4, 1];\n\n // 計算加權總和\n let sum = 0;\n for (let i = 0; i < 8; i++) {\n let product = digits[i]! * weights[i]!;\n\n // 如果乘積為兩位數,將十位數和個位數相加\n if (product >= 10) {\n product = Math.floor(product / 10) + (product % 10);\n }\n\n sum += product;\n }\n\n // 特殊情況:第7位數字為7時\n // 如果第7位數字為7且總和除以10的餘數為1,也視為有效\n const isValid = sum % 10 === 0 || (digits[6]! === 7 && sum % 10 === 1);\n\n return {\n isValid,\n message: isValid ? undefined : \"統一編號檢查碼錯誤\",\n };\n}\n","import type { ValidationResult, ResidentCertificateType } from \"../types\";\n\n/**\n * 字母對應數字表(用於居留證號驗證)\n */\nconst LETTER_MAPPING: Record<string, number> = {\n A: 10,\n B: 11,\n C: 12,\n D: 13,\n E: 14,\n F: 15,\n G: 16,\n H: 17,\n I: 34,\n J: 18,\n K: 19,\n L: 20,\n M: 21,\n N: 22,\n O: 35,\n P: 23,\n Q: 24,\n R: 25,\n S: 26,\n T: 27,\n U: 28,\n V: 29,\n W: 32,\n X: 30,\n Y: 31,\n Z: 33,\n};\n\n/**\n * 驗證舊式居留證號格式(1個字母 + 9個數字)\n * 格式:A800000000\n * - 第一個字元:地區代碼(A、B、C 或 D 表示外國人士)\n * - 第二個字元:性別/類型(8 = 男性,9 = 女性)\n * - 最後一個字元:檢查碼\n */\nfunction validateOldFormat(id: string): boolean {\n const pattern = /^[A-D][89]\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const letter = id[0] as string;\n const numbers = id.slice(1);\n\n const letterValue = LETTER_MAPPING[letter] as number;\n\n // 計算檢查碼(與身分證字號相同的演算法)\n const d1 = Math.floor(letterValue / 10);\n const d2 = letterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1];\n const digits = [d1, d2, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 驗證新式居留證號格式(2個字母 + 8個數字)\n * 格式:AA12345678\n * - 第一個字元:地區代碼(字母)\n * - 第二個字元:性別(8 = 男性,9 = 女性)以字母表示\n * - 最後一個字元:檢查碼\n */\nfunction validateNewFormat(id: string): boolean {\n const pattern = /^[A-Z]{2}\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const firstLetter = id[0] as string;\n const secondLetter = id[1] as string;\n const numbers = id.slice(2);\n\n const firstLetterValue = LETTER_MAPPING[firstLetter] as number;\n const secondLetterValue = LETTER_MAPPING[secondLetter] as number;\n\n // 計算新式格式的檢查碼\n const d1 = Math.floor(firstLetterValue / 10);\n const d2 = firstLetterValue % 10;\n const d3 = Math.floor(secondLetterValue / 10);\n const d4 = secondLetterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 1];\n const digits = [d1, d2, d3, d4, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 偵測居留證號格式類型\n */\nfunction detectFormat(id: string): ResidentCertificateType | null {\n if (/^[A-D][89]\\d{8}$/.test(id)) {\n return \"old\";\n }\n if (/^[A-Z]{2}\\d{8}$/.test(id)) {\n return \"new\";\n }\n return null;\n}\n\n/**\n * 驗證台灣居留證號(支援新舊格式)\n * @param id - 要驗證的居留證號\n * @param format - 可選:指定格式類型('old' 或 'new')\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateResidentCertificate('A800000000'); // 舊式格式\n * validateResidentCertificate('AA12345678'); // 新式格式\n * ```\n */\nexport function validateResidentCertificate(\n id: string,\n format?: ResidentCertificateType,\n): ValidationResult {\n if (!id || typeof id !== \"string\") {\n return {\n isValid: false,\n message: \"居留證號必須為非空字串\",\n };\n }\n\n const normalizedId = id.trim().toUpperCase();\n\n // 如果指定了格式,只驗證該格式\n if (format === \"old\") {\n const isValid = validateOldFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的舊式居留證號\",\n };\n }\n\n if (format === \"new\") {\n const isValid = validateNewFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的新式居留證號\",\n };\n }\n\n // 自動偵測格式\n const detectedFormat = detectFormat(normalizedId);\n\n if (!detectedFormat) {\n return {\n isValid: false,\n message: \"無效的居留證號格式\",\n };\n }\n\n const isValid =\n detectedFormat === \"old\"\n ? validateOldFormat(normalizedId)\n : validateNewFormat(normalizedId);\n\n return {\n isValid,\n message: isValid\n ? undefined\n : `無效的${detectedFormat === \"old\" ? \"舊式\" : \"新式\"}居留證號`,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣手機號碼\n * 格式:09XXXXXXXX(10位數字,以09開頭)\n *\n * @param phone - 要驗證的手機號碼\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateMobilePhone('0912345678');\n * validateMobilePhone('0912-345-678'); // 含分隔符號\n * ```\n */\nexport function validateMobilePhone(phone: string): ValidationResult {\n if (!phone || typeof phone !== \"string\") {\n return {\n isValid: false,\n message: \"手機號碼必須為非空字串\",\n };\n }\n\n // 移除常見的分隔符號(空格、破折號、括號)\n const normalized = phone.trim().replace(/[\\s\\-()]/g, \"\");\n\n // 檢查是否符合台灣手機號碼格式\n // 以09開頭且總共10位數字\n const pattern = /^09\\d{8}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"手機號碼必須以09開頭且為10位數字\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣自然人憑證編號\n * 格式:2個大寫英文字母 + 14位數字\n * 範例:AB12345678901234\n *\n * @param certNumber - 要驗證的自然人憑證編號\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateCitizenCertificate('AB12345678901234');\n * ```\n */\nexport function validateCitizenCertificate(\n certNumber: string,\n): ValidationResult {\n if (!certNumber || typeof certNumber !== \"string\") {\n return {\n isValid: false,\n message: \"自然人憑證編號必須為非空字串\",\n };\n }\n\n const normalized = certNumber.trim().toUpperCase();\n\n // 檢查格式:2個字母 + 14位數字\n const pattern = /^[A-Z]{2}\\d{14}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"自然人憑證編號必須為2個英文字母加上14位數字\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣電子發票手機條碼\n * 格式:/ + 7個字元(大寫英文字母、數字、+、-、.)\n * 範例:/ABCD123\n *\n * 手機條碼用於將電子發票儲存在手機載具中\n *\n * @param barcode - 要驗證的手機條碼\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateEInvoiceMobileBarcode('/ABCD123');\n * validateEInvoiceMobileBarcode('/1234567');\n * ```\n */\nexport function validateEInvoiceMobileBarcode(\n barcode: string,\n): ValidationResult {\n if (!barcode || typeof barcode !== \"string\") {\n return {\n isValid: false,\n message: \"手機條碼必須為非空字串\",\n };\n }\n\n const normalized = barcode.trim().toUpperCase();\n\n // 檢查格式:以 / 開頭,後接7個字元\n // 有效字元:A-Z、0-9、+、-、.\n const pattern = /^\\/[A-Z0-9+.-]{7}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"手機條碼必須以 / 開頭,後接7個有效字元(A-Z、0-9、+、-、.)\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣電子發票捐贈碼\n * 格式:3-7位數字\n * 範例:123、12345、1234567\n *\n * 捐贈碼用於將電子發票捐贈給已註冊的慈善機構\n *\n * @param code - 要驗證的捐贈碼\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateEInvoiceDonationCode('123');\n * validateEInvoiceDonationCode('12345');\n * ```\n */\nexport function validateEInvoiceDonationCode(code: string): ValidationResult {\n if (!code || typeof code !== \"string\") {\n return {\n isValid: false,\n message: \"捐贈碼必須為非空字串\",\n };\n }\n\n const normalized = code.trim();\n\n // 檢查格式:3-7位數字\n const pattern = /^\\d{3,7}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"捐贈碼必須為3至7位數字\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface ValidationResult {
|
|
2
|
+
isValid: boolean;
|
|
3
|
+
message?: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
type Gender = "male" | "female";
|
|
6
|
+
type ResidentCertificateType = "old" | "new";
|
|
7
|
+
type NationalIdType = "old" | "new";
|
|
8
|
+
|
|
9
|
+
declare function validateNationalId(id: string, format?: NationalIdType): ValidationResult;
|
|
10
|
+
|
|
11
|
+
declare function validateBusinessNumber(number: string): ValidationResult;
|
|
12
|
+
|
|
13
|
+
declare function validateResidentCertificate(id: string, format?: ResidentCertificateType): ValidationResult;
|
|
14
|
+
|
|
15
|
+
declare function validateMobilePhone(phone: string): ValidationResult;
|
|
16
|
+
|
|
17
|
+
declare function validateCitizenCertificate(certNumber: string): ValidationResult;
|
|
18
|
+
|
|
19
|
+
declare function validateEInvoiceMobileBarcode(barcode: string): ValidationResult;
|
|
20
|
+
|
|
21
|
+
declare function validateEInvoiceDonationCode(code: string): ValidationResult;
|
|
22
|
+
|
|
23
|
+
export { type Gender, type NationalIdType, type ResidentCertificateType, type ValidationResult, validateBusinessNumber, validateCitizenCertificate, validateEInvoiceDonationCode, validateEInvoiceMobileBarcode, validateMobilePhone, validateNationalId, validateResidentCertificate };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface ValidationResult {
|
|
2
|
+
isValid: boolean;
|
|
3
|
+
message?: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
type Gender = "male" | "female";
|
|
6
|
+
type ResidentCertificateType = "old" | "new";
|
|
7
|
+
type NationalIdType = "old" | "new";
|
|
8
|
+
|
|
9
|
+
declare function validateNationalId(id: string, format?: NationalIdType): ValidationResult;
|
|
10
|
+
|
|
11
|
+
declare function validateBusinessNumber(number: string): ValidationResult;
|
|
12
|
+
|
|
13
|
+
declare function validateResidentCertificate(id: string, format?: ResidentCertificateType): ValidationResult;
|
|
14
|
+
|
|
15
|
+
declare function validateMobilePhone(phone: string): ValidationResult;
|
|
16
|
+
|
|
17
|
+
declare function validateCitizenCertificate(certNumber: string): ValidationResult;
|
|
18
|
+
|
|
19
|
+
declare function validateEInvoiceMobileBarcode(barcode: string): ValidationResult;
|
|
20
|
+
|
|
21
|
+
declare function validateEInvoiceDonationCode(code: string): ValidationResult;
|
|
22
|
+
|
|
23
|
+
export { type Gender, type NationalIdType, type ResidentCertificateType, type ValidationResult, validateBusinessNumber, validateCitizenCertificate, validateEInvoiceDonationCode, validateEInvoiceMobileBarcode, validateMobilePhone, validateNationalId, validateResidentCertificate };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var V={A:10,B:11,C:12,D:13,E:14,F:15,G:16,H:17,I:34,J:18,K:19,L:20,M:21,N:22,O:35,P:23,Q:24,R:25,S:26,T:27,U:28,V:29,W:32,X:30,Y:31,Z:33};function R(t){if(!/^[A-Z][12]\d{8}$/.test(t))return false;let s=t[0],i=t.slice(1),r=V[s],e=Math.floor(r/10),a=r%10,o=[1,9,8,7,6,5,4,3,2,1,1];return [e,a,...i.split("").map(Number)].reduce((d,u,f)=>d+u*o[f],0)%10===0}function v(t){if(!/^[A-Z]{2}\d{8}$/.test(t))return false;let s=t[0],i=t[1],r=t.slice(2),e=V[s],a=V[i],o=Math.floor(e/10),l=e%10,c=Math.floor(a/10),d=a%10,u=[1,9,8,7,6,5,4,3,2,1,1,1];return [o,l,c,d,...r.split("").map(Number)].reduce((m,p,g)=>m+p*u[g],0)%10===0}function I(t){return /^[A-Z][12]\d{8}$/.test(t)?"old":/^[A-Z]{2}\d{8}$/.test(t)?"new":null}function x(t,n){if(!t||typeof t!="string")return {isValid:false,message:"\u8EAB\u5206\u8B49\u5B57\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let s=t.trim().toUpperCase();if(n==="old"){let e=R(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u820A\u5F0F\u8EAB\u5206\u8B49\u5B57\u865F"}}if(n==="new"){let e=v(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u65B0\u5F0F\u8EAB\u5206\u8B49\u5B57\u865F"}}let i=I(s);if(!i)return {isValid:false,message:"\u7121\u6548\u7684\u8EAB\u5206\u8B49\u5B57\u865F\u683C\u5F0F"};let r=i==="old"?R(s):v(s);return {isValid:r,message:r?void 0:`\u7121\u6548\u7684${i==="old"?"\u820A\u5F0F":"\u65B0\u5F0F"}\u8EAB\u5206\u8B49\u5B57\u865F`}}function A(t){if(!t||typeof t!="string")return {isValid:false,message:"\u7D71\u4E00\u7DE8\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim();if(!/^\d{8}$/.test(n))return {isValid:false,message:"\u7D71\u4E00\u7DE8\u865F\u5FC5\u9808\u70BA8\u4F4D\u6578\u5B57"};let i=n.split("").map(Number),r=[1,2,1,2,1,2,4,1],e=0;for(let o=0;o<8;o++){let l=i[o]*r[o];l>=10&&(l=Math.floor(l/10)+l%10),e+=l;}let a=e%10===0||i[6]===7&&e%10===1;return {isValid:a,message:a?void 0:"\u7D71\u4E00\u7DE8\u865F\u6AA2\u67E5\u78BC\u932F\u8AA4"}}var y={A:10,B:11,C:12,D:13,E:14,F:15,G:16,H:17,I:34,J:18,K:19,L:20,M:21,N:22,O:35,P:23,Q:24,R:25,S:26,T:27,U:28,V:29,W:32,X:30,Y:31,Z:33};function b(t){if(!/^[A-D][89]\d{8}$/.test(t))return false;let s=t[0],i=t.slice(1),r=y[s],e=Math.floor(r/10),a=r%10,o=[1,9,8,7,6,5,4,3,2,1,1];return [e,a,...i.split("").map(Number)].reduce((d,u,f)=>d+u*o[f],0)%10===0}function C(t){if(!/^[A-Z]{2}\d{8}$/.test(t))return false;let s=t[0],i=t[1],r=t.slice(2),e=y[s],a=y[i],o=Math.floor(e/10),l=e%10,c=Math.floor(a/10),d=a%10,u=[1,9,8,7,6,5,4,3,2,1,1,1];return [o,l,c,d,...r.split("").map(Number)].reduce((m,p,g)=>m+p*u[g],0)%10===0}function M(t){return /^[A-D][89]\d{8}$/.test(t)?"old":/^[A-Z]{2}\d{8}$/.test(t)?"new":null}function $(t,n){if(!t||typeof t!="string")return {isValid:false,message:"\u5C45\u7559\u8B49\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let s=t.trim().toUpperCase();if(n==="old"){let e=b(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u820A\u5F0F\u5C45\u7559\u8B49\u865F"}}if(n==="new"){let e=C(s);return {isValid:e,message:e?void 0:"\u7121\u6548\u7684\u65B0\u5F0F\u5C45\u7559\u8B49\u865F"}}let i=M(s);if(!i)return {isValid:false,message:"\u7121\u6548\u7684\u5C45\u7559\u8B49\u865F\u683C\u5F0F"};let r=i==="old"?b(s):C(s);return {isValid:r,message:r?void 0:`\u7121\u6548\u7684${i==="old"?"\u820A\u5F0F":"\u65B0\u5F0F"}\u5C45\u7559\u8B49\u865F`}}function T(t){if(!t||typeof t!="string")return {isValid:false,message:"\u624B\u6A5F\u865F\u78BC\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim().replace(/[\s\-()]/g,"");return /^09\d{8}$/.test(n)?{isValid:true}:{isValid:false,message:"\u624B\u6A5F\u865F\u78BC\u5FC5\u9808\u4EE509\u958B\u982D\u4E14\u70BA10\u4F4D\u6578\u5B57"}}function h(t){if(!t||typeof t!="string")return {isValid:false,message:"\u81EA\u7136\u4EBA\u6191\u8B49\u7DE8\u865F\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim().toUpperCase();return /^[A-Z]{2}\d{14}$/.test(n)?{isValid:true}:{isValid:false,message:"\u81EA\u7136\u4EBA\u6191\u8B49\u7DE8\u865F\u5FC5\u9808\u70BA2\u500B\u82F1\u6587\u5B57\u6BCD\u52A0\u4E0A14\u4F4D\u6578\u5B57"}}function L(t){if(!t||typeof t!="string")return {isValid:false,message:"\u624B\u6A5F\u689D\u78BC\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim().toUpperCase();return /^\/[A-Z0-9+.-]{7}$/.test(n)?{isValid:true}:{isValid:false,message:"\u624B\u6A5F\u689D\u78BC\u5FC5\u9808\u4EE5 / \u958B\u982D\uFF0C\u5F8C\u63A57\u500B\u6709\u6548\u5B57\u5143\uFF08A-Z\u30010-9\u3001+\u3001-\u3001.\uFF09"}}function w(t){if(!t||typeof t!="string")return {isValid:false,message:"\u6350\u8D08\u78BC\u5FC5\u9808\u70BA\u975E\u7A7A\u5B57\u4E32"};let n=t.trim();return /^\d{3,7}$/.test(n)?{isValid:true}:{isValid:false,message:"\u6350\u8D08\u78BC\u5FC5\u9808\u70BA3\u81F37\u4F4D\u6578\u5B57"}}export{A as validateBusinessNumber,h as validateCitizenCertificate,w as validateEInvoiceDonationCode,L as validateEInvoiceMobileBarcode,T as validateMobilePhone,x as validateNationalId,$ as validateResidentCertificate};//# sourceMappingURL=index.mjs.map
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validators/national-id.ts","../src/validators/business-number.ts","../src/validators/resident-certificate.ts","../src/validators/mobile-phone.ts","../src/validators/citizen-certificate.ts","../src/validators/einvoice-mobile-barcode.ts","../src/validators/einvoice-donation-code.ts"],"names":["LETTER_MAPPING","validateOldFormat","id","letter","numbers","letterValue","d1","d2","weights","acc","digit","index","validateNewFormat","firstLetter","secondLetter","firstLetterValue","secondLetterValue","d3","d4","detectFormat","validateNationalId","format","normalizedId","isValid","detectedFormat","validateBusinessNumber","number","normalized","digits","sum","i","product","validateResidentCertificate","validateMobilePhone","phone","validateCitizenCertificate","certNumber","validateEInvoiceMobileBarcode","barcode","validateEInvoiceDonationCode","code"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ValidationResult, NationalIdType } from \"../types\";\n\n/**\n * 字母對應數字表(用於身分證字號驗證)\n */\nconst LETTER_MAPPING: Record<string, number> = {\n A: 10,\n B: 11,\n C: 12,\n D: 13,\n E: 14,\n F: 15,\n G: 16,\n H: 17,\n I: 34,\n J: 18,\n K: 19,\n L: 20,\n M: 21,\n N: 22,\n O: 35,\n P: 23,\n Q: 24,\n R: 25,\n S: 26,\n T: 27,\n U: 28,\n V: 29,\n W: 32,\n X: 30,\n Y: 31,\n Z: 33,\n};\n\n/**\n * 驗證舊式身分證字號格式(1個字母 + 9個數字)\n * 格式:A123456789\n * - 第一個字元:地區代碼(字母)\n * - 第二個字元:性別(1 = 男性,2 = 女性)\n * - 最後一個字元:檢查碼\n */\nfunction validateOldFormat(id: string): boolean {\n const pattern = /^[A-Z][12]\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const letter = id[0] as string;\n const numbers = id.slice(1);\n\n const letterValue = LETTER_MAPPING[letter] as number;\n\n // 計算檢查碼\n const d1 = Math.floor(letterValue / 10);\n const d2 = letterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1];\n const digits = [d1, d2, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 驗證新式身分證字號格式(2個字母 + 8個數字)\n * 格式:AA12345678\n * - 第一個字元:地區代碼(字母)\n * - 第二個字元:性別(8 = 男性,9 = 女性)以字母表示\n * - 最後一個字元:檢查碼\n */\nfunction validateNewFormat(id: string): boolean {\n const pattern = /^[A-Z]{2}\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const firstLetter = id[0] as string;\n const secondLetter = id[1] as string;\n const numbers = id.slice(2);\n\n const firstLetterValue = LETTER_MAPPING[firstLetter] as number;\n const secondLetterValue = LETTER_MAPPING[secondLetter] as number;\n\n // 計算新式格式的檢查碼\n const d1 = Math.floor(firstLetterValue / 10);\n const d2 = firstLetterValue % 10;\n const d3 = Math.floor(secondLetterValue / 10);\n const d4 = secondLetterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 1];\n const digits = [d1, d2, d3, d4, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 偵測身分證字號格式類型\n */\nfunction detectFormat(id: string): NationalIdType | null {\n if (/^[A-Z][12]\\d{8}$/.test(id)) {\n return \"old\";\n }\n if (/^[A-Z]{2}\\d{8}$/.test(id)) {\n return \"new\";\n }\n return null;\n}\n\n/**\n * 驗證台灣身分證字號(支援新舊格式)\n * @param id - 要驗證的身分證字號\n * @param format - 可選:指定格式類型('old' 或 'new')\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateNationalId('A123456789'); // 舊式格式\n * validateNationalId('AA12345678'); // 新式格式\n * ```\n */\nexport function validateNationalId(\n id: string,\n format?: NationalIdType,\n): ValidationResult {\n if (!id || typeof id !== \"string\") {\n return {\n isValid: false,\n message: \"身分證字號必須為非空字串\",\n };\n }\n\n const normalizedId = id.trim().toUpperCase();\n\n // 如果指定了格式,只驗證該格式\n if (format === \"old\") {\n const isValid = validateOldFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的舊式身分證字號\",\n };\n }\n\n if (format === \"new\") {\n const isValid = validateNewFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的新式身分證字號\",\n };\n }\n\n // 自動偵測格式\n const detectedFormat = detectFormat(normalizedId);\n\n if (!detectedFormat) {\n return {\n isValid: false,\n message: \"無效的身分證字號格式\",\n };\n }\n\n const isValid =\n detectedFormat === \"old\"\n ? validateOldFormat(normalizedId)\n : validateNewFormat(normalizedId);\n\n return {\n isValid,\n message: isValid\n ? undefined\n : `無效的${detectedFormat === \"old\" ? \"舊式\" : \"新式\"}身分證字號`,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣營利事業統一編號\n * 格式:8位數字\n * 使用加權檢查碼演算法\n *\n * @param number - 要驗證的統一編號\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateBusinessNumber('12345678');\n * ```\n */\nexport function validateBusinessNumber(number: string): ValidationResult {\n if (!number || typeof number !== \"string\") {\n return {\n isValid: false,\n message: \"統一編號必須為非空字串\",\n };\n }\n\n const normalized = number.trim();\n\n // 檢查是否為8位數字\n const pattern = /^\\d{8}$/;\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"統一編號必須為8位數字\",\n };\n }\n\n const digits = normalized.split(\"\").map(Number);\n const weights = [1, 2, 1, 2, 1, 2, 4, 1];\n\n // 計算加權總和\n let sum = 0;\n for (let i = 0; i < 8; i++) {\n let product = digits[i]! * weights[i]!;\n\n // 如果乘積為兩位數,將十位數和個位數相加\n if (product >= 10) {\n product = Math.floor(product / 10) + (product % 10);\n }\n\n sum += product;\n }\n\n // 特殊情況:第7位數字為7時\n // 如果第7位數字為7且總和除以10的餘數為1,也視為有效\n const isValid = sum % 10 === 0 || (digits[6]! === 7 && sum % 10 === 1);\n\n return {\n isValid,\n message: isValid ? undefined : \"統一編號檢查碼錯誤\",\n };\n}\n","import type { ValidationResult, ResidentCertificateType } from \"../types\";\n\n/**\n * 字母對應數字表(用於居留證號驗證)\n */\nconst LETTER_MAPPING: Record<string, number> = {\n A: 10,\n B: 11,\n C: 12,\n D: 13,\n E: 14,\n F: 15,\n G: 16,\n H: 17,\n I: 34,\n J: 18,\n K: 19,\n L: 20,\n M: 21,\n N: 22,\n O: 35,\n P: 23,\n Q: 24,\n R: 25,\n S: 26,\n T: 27,\n U: 28,\n V: 29,\n W: 32,\n X: 30,\n Y: 31,\n Z: 33,\n};\n\n/**\n * 驗證舊式居留證號格式(1個字母 + 9個數字)\n * 格式:A800000000\n * - 第一個字元:地區代碼(A、B、C 或 D 表示外國人士)\n * - 第二個字元:性別/類型(8 = 男性,9 = 女性)\n * - 最後一個字元:檢查碼\n */\nfunction validateOldFormat(id: string): boolean {\n const pattern = /^[A-D][89]\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const letter = id[0] as string;\n const numbers = id.slice(1);\n\n const letterValue = LETTER_MAPPING[letter] as number;\n\n // 計算檢查碼(與身分證字號相同的演算法)\n const d1 = Math.floor(letterValue / 10);\n const d2 = letterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1];\n const digits = [d1, d2, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 驗證新式居留證號格式(2個字母 + 8個數字)\n * 格式:AA12345678\n * - 第一個字元:地區代碼(字母)\n * - 第二個字元:性別(8 = 男性,9 = 女性)以字母表示\n * - 最後一個字元:檢查碼\n */\nfunction validateNewFormat(id: string): boolean {\n const pattern = /^[A-Z]{2}\\d{8}$/;\n if (!pattern.test(id)) {\n return false;\n }\n\n const firstLetter = id[0] as string;\n const secondLetter = id[1] as string;\n const numbers = id.slice(2);\n\n const firstLetterValue = LETTER_MAPPING[firstLetter] as number;\n const secondLetterValue = LETTER_MAPPING[secondLetter] as number;\n\n // 計算新式格式的檢查碼\n const d1 = Math.floor(firstLetterValue / 10);\n const d2 = firstLetterValue % 10;\n const d3 = Math.floor(secondLetterValue / 10);\n const d4 = secondLetterValue % 10;\n\n const weights = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 1];\n const digits = [d1, d2, d3, d4, ...numbers.split(\"\").map(Number)];\n\n const sum = digits.reduce(\n (acc, digit, index) => acc + digit * weights[index]!,\n 0,\n );\n\n return sum % 10 === 0;\n}\n\n/**\n * 偵測居留證號格式類型\n */\nfunction detectFormat(id: string): ResidentCertificateType | null {\n if (/^[A-D][89]\\d{8}$/.test(id)) {\n return \"old\";\n }\n if (/^[A-Z]{2}\\d{8}$/.test(id)) {\n return \"new\";\n }\n return null;\n}\n\n/**\n * 驗證台灣居留證號(支援新舊格式)\n * @param id - 要驗證的居留證號\n * @param format - 可選:指定格式類型('old' 或 'new')\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateResidentCertificate('A800000000'); // 舊式格式\n * validateResidentCertificate('AA12345678'); // 新式格式\n * ```\n */\nexport function validateResidentCertificate(\n id: string,\n format?: ResidentCertificateType,\n): ValidationResult {\n if (!id || typeof id !== \"string\") {\n return {\n isValid: false,\n message: \"居留證號必須為非空字串\",\n };\n }\n\n const normalizedId = id.trim().toUpperCase();\n\n // 如果指定了格式,只驗證該格式\n if (format === \"old\") {\n const isValid = validateOldFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的舊式居留證號\",\n };\n }\n\n if (format === \"new\") {\n const isValid = validateNewFormat(normalizedId);\n return {\n isValid,\n message: isValid ? undefined : \"無效的新式居留證號\",\n };\n }\n\n // 自動偵測格式\n const detectedFormat = detectFormat(normalizedId);\n\n if (!detectedFormat) {\n return {\n isValid: false,\n message: \"無效的居留證號格式\",\n };\n }\n\n const isValid =\n detectedFormat === \"old\"\n ? validateOldFormat(normalizedId)\n : validateNewFormat(normalizedId);\n\n return {\n isValid,\n message: isValid\n ? undefined\n : `無效的${detectedFormat === \"old\" ? \"舊式\" : \"新式\"}居留證號`,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣手機號碼\n * 格式:09XXXXXXXX(10位數字,以09開頭)\n *\n * @param phone - 要驗證的手機號碼\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateMobilePhone('0912345678');\n * validateMobilePhone('0912-345-678'); // 含分隔符號\n * ```\n */\nexport function validateMobilePhone(phone: string): ValidationResult {\n if (!phone || typeof phone !== \"string\") {\n return {\n isValid: false,\n message: \"手機號碼必須為非空字串\",\n };\n }\n\n // 移除常見的分隔符號(空格、破折號、括號)\n const normalized = phone.trim().replace(/[\\s\\-()]/g, \"\");\n\n // 檢查是否符合台灣手機號碼格式\n // 以09開頭且總共10位數字\n const pattern = /^09\\d{8}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"手機號碼必須以09開頭且為10位數字\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣自然人憑證編號\n * 格式:2個大寫英文字母 + 14位數字\n * 範例:AB12345678901234\n *\n * @param certNumber - 要驗證的自然人憑證編號\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateCitizenCertificate('AB12345678901234');\n * ```\n */\nexport function validateCitizenCertificate(\n certNumber: string,\n): ValidationResult {\n if (!certNumber || typeof certNumber !== \"string\") {\n return {\n isValid: false,\n message: \"自然人憑證編號必須為非空字串\",\n };\n }\n\n const normalized = certNumber.trim().toUpperCase();\n\n // 檢查格式:2個字母 + 14位數字\n const pattern = /^[A-Z]{2}\\d{14}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"自然人憑證編號必須為2個英文字母加上14位數字\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣電子發票手機條碼\n * 格式:/ + 7個字元(大寫英文字母、數字、+、-、.)\n * 範例:/ABCD123\n *\n * 手機條碼用於將電子發票儲存在手機載具中\n *\n * @param barcode - 要驗證的手機條碼\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateEInvoiceMobileBarcode('/ABCD123');\n * validateEInvoiceMobileBarcode('/1234567');\n * ```\n */\nexport function validateEInvoiceMobileBarcode(\n barcode: string,\n): ValidationResult {\n if (!barcode || typeof barcode !== \"string\") {\n return {\n isValid: false,\n message: \"手機條碼必須為非空字串\",\n };\n }\n\n const normalized = barcode.trim().toUpperCase();\n\n // 檢查格式:以 / 開頭,後接7個字元\n // 有效字元:A-Z、0-9、+、-、.\n const pattern = /^\\/[A-Z0-9+.-]{7}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"手機條碼必須以 / 開頭,後接7個有效字元(A-Z、0-9、+、-、.)\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * 驗證台灣電子發票捐贈碼\n * 格式:3-7位數字\n * 範例:123、12345、1234567\n *\n * 捐贈碼用於將電子發票捐贈給已註冊的慈善機構\n *\n * @param code - 要驗證的捐贈碼\n * @returns 驗證結果\n *\n * @example\n * ```typescript\n * validateEInvoiceDonationCode('123');\n * validateEInvoiceDonationCode('12345');\n * ```\n */\nexport function validateEInvoiceDonationCode(code: string): ValidationResult {\n if (!code || typeof code !== \"string\") {\n return {\n isValid: false,\n message: \"捐贈碼必須為非空字串\",\n };\n }\n\n const normalized = code.trim();\n\n // 檢查格式:3-7位數字\n const pattern = /^\\d{3,7}$/;\n\n if (!pattern.test(normalized)) {\n return {\n isValid: false,\n message: \"捐贈碼必須為3至7位數字\",\n };\n }\n\n return {\n isValid: true,\n };\n}\n"]}
|