bahttext 2.2.0 → 2.3.1
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-en.md +1 -0
- package/README.md +1 -1
- package/package.json +8 -8
- package/src/index.js +58 -33
- package/src/index.test.js +0 -119
package/README-en.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# bahttext
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/bahttext)
|
|
4
|
+
[](https://www.npmjs.com/package/bahttext)
|
|
4
5
|
[](http://opensource.org/licenses/MIT)
|
|
5
6
|
[](https://github.com/semantic-release/semantic-release) [](https://greenkeeper.io/)
|
|
6
7
|
[](https://codecov.io/github/jojoee/bahttext)
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# bahttext
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/bahttext)
|
|
4
|
+
[](https://www.npmjs.com/package/bahttext)
|
|
4
5
|
[](http://opensource.org/licenses/MIT)
|
|
5
6
|
[](https://github.com/semantic-release/semantic-release) [](https://greenkeeper.io/)
|
|
6
7
|
[](https://codecov.io/github/jojoee/bahttext)
|
|
@@ -93,4 +94,3 @@ bahttext(-0.20) // ลบยี่สิบสตางค์
|
|
|
93
94
|
- [Google Sheets BAHTTEXT function](https://support.google.com/docs/answer/9982303?hl=en)
|
|
94
95
|
- [Microsoft Office's BAHTTEXT function](https://support.office.com/en-us/article/BAHTTEXT-function-5ba4d0b4-abd3-4325-8d22-7a92d59aab9c)
|
|
95
96
|
- แรงบัลดาลใจจาก [earthchie/BAHTTEXT.js](https://github.com/earthchie/BAHTTEXT.js)
|
|
96
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bahttext",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Change number to Thai pronunciation string",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"typings": "src/index.d.ts",
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/jojoee/bahttext#readme",
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@stryker-mutator/core": "^
|
|
39
|
-
"@stryker-mutator/jest-runner": "^
|
|
38
|
+
"@stryker-mutator/core": "^8.7.1",
|
|
39
|
+
"@stryker-mutator/jest-runner": "^8.7.1",
|
|
40
40
|
"@to-da-moon/thai-baht-lib": "^0.0.12",
|
|
41
41
|
"baht": "^0.7.1",
|
|
42
|
-
"jest": "^
|
|
43
|
-
"jest-expect-message": "^1.
|
|
44
|
-
"semantic-release": "^
|
|
45
|
-
"standard": "^
|
|
46
|
-
"thai-baht-text": "^
|
|
42
|
+
"jest": "^29.7.0",
|
|
43
|
+
"jest-expect-message": "^1.1.3",
|
|
44
|
+
"semantic-release": "^24.2.2",
|
|
45
|
+
"standard": "^17.1.2",
|
|
46
|
+
"thai-baht-text": "^2.0.5",
|
|
47
47
|
"thai-baht-text-ts": "^1.1.0",
|
|
48
48
|
"typescript": "*"
|
|
49
49
|
},
|
package/src/index.js
CHANGED
|
@@ -4,28 +4,56 @@ const bahtxtConst = {
|
|
|
4
4
|
placeNameStrs: ['', 'สิบ', 'ร้อย', 'พัน', 'หมื่น', 'แสน', 'ล้าน']
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
const GrammarFixs = [
|
|
8
|
+
{ pat: /หนึ่งสิบ/g, replace: 'สิบ' },
|
|
9
|
+
{ pat: /สองสิบ/g, replace: 'ยี่สิบ' },
|
|
10
|
+
{ pat: /สิบหนึ่ง/g, replace: 'สิบเอ็ด' }
|
|
11
|
+
]
|
|
12
|
+
|
|
7
13
|
/**
|
|
8
14
|
* @private
|
|
9
15
|
* @param {number[]} nums
|
|
10
16
|
* @returns {string}
|
|
11
17
|
*/
|
|
12
18
|
function bahtxtNum2Word (nums) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Converts a numeric string (or legacy digit array) into Thai words without unit suffix.
|
|
21
|
+
* The new implementation iterates over the input string directly, eliminating
|
|
22
|
+
* the intermediate `Array.from(...).map(Number)` allocations previously used.
|
|
23
|
+
*
|
|
24
|
+
* @param {string|number[]} nums – string of digits ("123") or array \[1,2,3].
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
let numStr = ''
|
|
28
|
+
|
|
29
|
+
if (typeof nums === 'string') {
|
|
30
|
+
numStr = nums
|
|
31
|
+
} else if (Array.isArray(nums)) {
|
|
32
|
+
numStr = nums.join('')
|
|
33
|
+
} else {
|
|
34
|
+
return ''
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Trim leading zeros but leave at least one digit so "0" stays "0"
|
|
38
|
+
numStr = numStr.replace(/^0+/, '') || '0'
|
|
39
|
+
|
|
40
|
+
const len = numStr.length
|
|
41
|
+
const maxLen = 7 // handle up to 6-digit group + 1-digit look-ahead for "ล้าน" logic
|
|
16
42
|
|
|
17
43
|
if (len > maxLen) {
|
|
18
|
-
// more than million
|
|
19
44
|
const overflowIndex = len - maxLen + 1
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
return bahtxtNum2Word(
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
const overflowStr = numStr.slice(0, overflowIndex)
|
|
46
|
+
const remainingStr = numStr.slice(overflowIndex)
|
|
47
|
+
return bahtxtNum2Word(overflowStr) + 'ล้าน' + bahtxtNum2Word(remainingStr)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let result = ''
|
|
51
|
+
for (let i = 0; i < len; i++) {
|
|
52
|
+
const digit = numStr.charCodeAt(i) - 48 // faster than parseInt(numStr[i], 10)
|
|
53
|
+
if (digit > 0) {
|
|
54
|
+
result +=
|
|
55
|
+
bahtxtConst.singleUnitStrs[digit] +
|
|
56
|
+
bahtxtConst.placeNameStrs[len - i - 1]
|
|
29
57
|
}
|
|
30
58
|
}
|
|
31
59
|
|
|
@@ -39,9 +67,10 @@ function bahtxtNum2Word (nums) {
|
|
|
39
67
|
* @returns {string}
|
|
40
68
|
*/
|
|
41
69
|
function bahtxtGrammarFix (str) {
|
|
42
|
-
|
|
43
|
-
.replace(
|
|
44
|
-
|
|
70
|
+
for (const GrammarFix of GrammarFixs) {
|
|
71
|
+
str = str.replace(GrammarFix.pat, GrammarFix.replace)
|
|
72
|
+
}
|
|
73
|
+
return str
|
|
45
74
|
}
|
|
46
75
|
|
|
47
76
|
/**
|
|
@@ -73,31 +102,27 @@ function bahtxtCombine (baht, satang) {
|
|
|
73
102
|
* @returns {string}
|
|
74
103
|
*/
|
|
75
104
|
function bahttext (num) {
|
|
76
|
-
if (
|
|
105
|
+
if (num === null || num === undefined || // explicit null/undefined check, allow 0
|
|
77
106
|
typeof num === 'boolean' || // no boolean
|
|
78
|
-
isNaN(Number(num)) || // must be
|
|
79
|
-
num < Number.MIN_SAFE_INTEGER || //
|
|
80
|
-
num > Number.MAX_SAFE_INTEGER
|
|
107
|
+
isNaN(Number(num)) || // must be numeric coercible
|
|
108
|
+
num < Number.MIN_SAFE_INTEGER || // outside JS safe integer range
|
|
109
|
+
num > Number.MAX_SAFE_INTEGER
|
|
81
110
|
) {
|
|
82
111
|
return bahtxtConst.defaultResult
|
|
83
112
|
}
|
|
84
113
|
|
|
85
|
-
//
|
|
86
|
-
const positiveNum = Math.abs(num)
|
|
114
|
+
// normalise sign & prepare parts
|
|
115
|
+
const positiveNum = Math.abs(Number(num))
|
|
87
116
|
|
|
88
|
-
|
|
89
|
-
const bahtStr = Math.floor(positiveNum).toString()
|
|
90
|
-
/** @type {string} */
|
|
91
|
-
const satangStr = (positiveNum % 1 * 100).toFixed(0)
|
|
117
|
+
const bahtPart = Math.floor(positiveNum)
|
|
92
118
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const satangArr = Array.from(satangStr).map(Number)
|
|
119
|
+
const bahtStr = String(bahtPart)
|
|
120
|
+
// Keep original rounding behaviour ("toFixed(0)") to avoid output drift
|
|
121
|
+
const satangStr = (positiveNum % 1 * 100).toFixed(0)
|
|
97
122
|
|
|
98
|
-
//
|
|
99
|
-
let baht = bahtxtNum2Word(
|
|
100
|
-
let satang = bahtxtNum2Word(
|
|
123
|
+
// Convert directly without creating intermediate digit arrays
|
|
124
|
+
let baht = bahtxtNum2Word(bahtStr)
|
|
125
|
+
let satang = bahtxtNum2Word(satangStr)
|
|
101
126
|
|
|
102
127
|
// grammar
|
|
103
128
|
baht = bahtxtGrammarFix(baht)
|
package/src/index.test.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
bahttext,
|
|
3
|
-
bahtxtGrammarFix: grammarFix,
|
|
4
|
-
bahtxtCombine: combine
|
|
5
|
-
} = require('./index')
|
|
6
|
-
const defaultResult = 'ศูนย์บาทถ้วน'
|
|
7
|
-
const groupedTestCasesKey = 'categoryCase'
|
|
8
|
-
const googleSheetTestCases = require('../misc/testcases.json').map(item => {
|
|
9
|
-
item[groupedTestCasesKey] = `${item.category}-${item.case}`
|
|
10
|
-
return item
|
|
11
|
-
})
|
|
12
|
-
jest.autoMockOff()
|
|
13
|
-
|
|
14
|
-
// TODO: move to somewhere else
|
|
15
|
-
// TODO: write test
|
|
16
|
-
function groupBy (arr, key) {
|
|
17
|
-
return arr.reduce((acc, curr) => {
|
|
18
|
-
acc[curr[key]] = (acc[curr[key]] || []).concat(curr)
|
|
19
|
-
return acc
|
|
20
|
-
}, {})
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const groupedTestCases = groupBy(googleSheetTestCases, groupedTestCasesKey)
|
|
24
|
-
|
|
25
|
-
// TODO: to be implemented
|
|
26
|
-
describe('num2Word', () => {
|
|
27
|
-
test('test', () => {
|
|
28
|
-
expect(true).toBeTruthy()
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
describe('grammarFix', () => {
|
|
33
|
-
test('replace "หนึ่งสิบ" with "สิบ"', () => {
|
|
34
|
-
expect(grammarFix('หนึ่งสิบหก')).toBe('สิบหก')
|
|
35
|
-
expect(grammarFix('หนึ่งสิบสี่')).toBe('สิบสี่')
|
|
36
|
-
expect(grammarFix('ห้าร้อยหนึ่งสิบสาม')).toBe('ห้าร้อยสิบสาม')
|
|
37
|
-
expect(grammarFix('สี่หมื่นหนึ่งสิบสาม')).toBe('สี่หมื่นสิบสาม')
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('replace "สองสิบ" with "ยี่สิบ"', () => {
|
|
41
|
-
expect(grammarFix('ห้าร้อยสองสิบหนึ่ง')).toBe('ห้าร้อยยี่สิบเอ็ด')
|
|
42
|
-
expect(grammarFix('สองสิบสี่')).toBe('ยี่สิบสี่')
|
|
43
|
-
expect(grammarFix('เก้าแสนหกหมื่นสามพันสามร้อยสองสิบสี่')).toBe('เก้าแสนหกหมื่นสามพันสามร้อยยี่สิบสี่')
|
|
44
|
-
expect(grammarFix('เจ็ดหมื่นห้าพันสี่ร้อยสองสิบหนึ่ง')).toBe('เจ็ดหมื่นห้าพันสี่ร้อยยี่สิบเอ็ด')
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('replace "สิบหนึ่ง" with "สิบเอ็ด"', () => {
|
|
48
|
-
expect(grammarFix('หนึ่งสิบหนึ่ง')).toBe('สิบเอ็ด')
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
describe('combine', () => {
|
|
53
|
-
test('both baht and satang are empty', () => {
|
|
54
|
-
expect(combine('', '')).toBe('ศูนย์บาทถ้วน')
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('both baht and satang are not empty', () => {
|
|
58
|
-
expect(combine('หนึ่งร้อยยี่สิบสาม', 'ห้าสิบหก')).toBe('หนึ่งร้อยยี่สิบสามบาทห้าสิบหกสตางค์')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('has only baht', () => {
|
|
62
|
-
expect(combine('แปดแสนเจ็ดหมื่นสี่พันห้าร้อยหกสิบสาม', '')).toBe('แปดแสนเจ็ดหมื่นสี่พันห้าร้อยหกสิบสามบาทถ้วน')
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('has only satang', () => {
|
|
66
|
-
expect(combine('', 'ลบสามสิบหก')).toBe('ลบสามสิบหกสตางค์')
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
describe('bahttext', () => {
|
|
71
|
-
test('invalid number', () => {
|
|
72
|
-
const zeroText = 'ศูนย์บาทถ้วน'
|
|
73
|
-
|
|
74
|
-
expect(bahttext(null)).toBe(zeroText)
|
|
75
|
-
expect(bahttext(true)).toBe(zeroText)
|
|
76
|
-
expect(bahttext(false)).toBe(zeroText)
|
|
77
|
-
expect(bahttext([])).toBe(zeroText)
|
|
78
|
-
expect(bahttext([1, 2, 3])).toBe(zeroText)
|
|
79
|
-
expect(bahttext({})).toBe(zeroText)
|
|
80
|
-
expect(bahttext('')).toBe(zeroText)
|
|
81
|
-
expect(bahttext()).toBe(zeroText)
|
|
82
|
-
expect(bahttext(undefined)).toBe(zeroText)
|
|
83
|
-
expect(bahttext('this-is-not-number')).toBe(zeroText)
|
|
84
|
-
expect(bahttext('it-must-be-number-only')).toBe(zeroText)
|
|
85
|
-
expect(bahttext('a123')).toBe(zeroText)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
test('leading with zero', () => {
|
|
89
|
-
expect(bahttext('0.1')).toBe('สิบสตางค์')
|
|
90
|
-
expect(bahttext('01.1')).toBe('หนึ่งบาทสิบสตางค์')
|
|
91
|
-
expect(bahttext('-01.1')).toBe('ลบหนึ่งบาทสิบสตางค์')
|
|
92
|
-
expect(bahttext('000.01')).toBe('หนึ่งสตางค์')
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('less than Number.MIN_SAFE_INTEGER', () => {
|
|
96
|
-
const items = [1, 20, 9451, 5656549]
|
|
97
|
-
for (let i = 0; i < items.length; i++) {
|
|
98
|
-
expect(bahttext(Number.MIN_SAFE_INTEGER - items[i])).toBe(defaultResult)
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
test('more than Number.MAX_SAFE_INTEGER', () => {
|
|
103
|
-
const items = [1, 20, 9451, 5656549]
|
|
104
|
-
for (let i = 0; i < items.length; i++) {
|
|
105
|
-
expect(bahttext(Number.MAX_SAFE_INTEGER + items[i])).toBe(defaultResult)
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
// numbers are imported from Google Sheets
|
|
110
|
-
for (const [groupedName, testCases] of Object.entries(groupedTestCases)) {
|
|
111
|
-
test(`imported Google Sheets: ${groupedName}`, () => {
|
|
112
|
-
for (let i = 0; i < testCases.length; i++) {
|
|
113
|
-
const customMessage = JSON.stringify(testCases[i])
|
|
114
|
-
const number = Number(testCases[i].number)
|
|
115
|
-
expect(bahttext(number), customMessage).toBe(testCases[i].text)
|
|
116
|
-
}
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
})
|