smart-unit 1.0.4 → 2.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.
@@ -0,0 +1,195 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var DecimalConstructor = require('decimal.js');
6
+ var utils = require('./utils-DqEXot5a.js');
7
+
8
+ class SmartUnitPrecision extends utils.SmartUnitBase {
9
+ constructor(units, option = {}) {
10
+ super(units, option);
11
+ this.DecimalClass = DecimalConstructor;
12
+ if (option.decimalOptions) {
13
+ this.DecimalClass = DecimalConstructor.clone(option.decimalOptions);
14
+ }
15
+ }
16
+ // 根据输入数值获取单位和调整后的值
17
+ /**
18
+ * Gets the appropriate unit and adjusted value for the input number
19
+ *
20
+ * @param num - The input NumPrecision to determine the unit for
21
+ * @param fractionDigits - Decimal precision configuration
22
+ * @returns The FormattedValue object containing the number, unit, and decimal instance
23
+ */
24
+ getUnit(num) {
25
+ if (Number.isNaN(num))
26
+ throw new Error(utils.ERROR_NAN_INPUT);
27
+ const unitDigitsLen = this.unitDigits.length;
28
+ const dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
29
+ const isNegative = dn.isNegative();
30
+ let absDn = isNegative ? dn.abs() : dn;
31
+ let i = 0;
32
+ while (i < unitDigitsLen) {
33
+ const digit = this.unitDigits[i];
34
+ if (absDn.lt(digit * this.threshold)) {
35
+ break;
36
+ }
37
+ absDn = absDn.dividedBy(digit);
38
+ i++;
39
+ }
40
+ const result = isNegative ? absDn.neg() : absDn;
41
+ const n = result.toNumber();
42
+ return {
43
+ num: n,
44
+ decimal: result,
45
+ unit: this.unitNames[i],
46
+ numStr: this.formatNumber(result, this.fractionDigits),
47
+ };
48
+ }
49
+ // 将数字转换为字符串表示形式,并可选择配置小数位数
50
+ /**
51
+ * Formats a number as a string with unit and optional decimal place configuration
52
+ *
53
+ * @param num - The input number to format
54
+ * @param fractionDigits - Decimal precision configuration
55
+ * @returns The formatted string with number and unit
56
+ */
57
+ format(num, fractionDigits = this.fractionDigits) {
58
+ const { decimal, unit } = this.getUnit(num);
59
+ const formatted = this.formatNumber(decimal, fractionDigits);
60
+ return `${formatted}${this.convert ? this.convert(unit) : unit}`;
61
+ }
62
+ // 根据输入数值获取链式单位数组
63
+ /**
64
+ * Gets the chain of units for the input number
65
+ *
66
+ * @param num - The input number to determine the chain for
67
+ * @returns An array of FormattedValue objects representing the chain of units
68
+ */
69
+ getChainUnit(num) {
70
+ if (Number.isNaN(num))
71
+ throw new Error(utils.ERROR_NAN_INPUT);
72
+ const result = [];
73
+ if (num === 0) {
74
+ return [{ num: 0, unit: this.unitNames[0], numStr: '0', decimal: new this.DecimalClass(0) }];
75
+ }
76
+ const dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
77
+ const isNegative = dn.isNegative();
78
+ let absDn = isNegative ? dn.abs() : dn;
79
+ for (let i = this.accumulatedDigits.length - 1; i >= 0; i--) {
80
+ const accDigit = this.accumulatedDigits[i];
81
+ if (absDn.gte(accDigit)) {
82
+ const res = absDn.dividedToIntegerBy(accDigit);
83
+ const val = isNegative ? res.neg() : res;
84
+ result.push({
85
+ num: val.toNumber(),
86
+ decimal: new this.DecimalClass(val),
87
+ unit: this.unitNames[i + 1],
88
+ numStr: this.formatNumber(val, this.fractionDigits),
89
+ });
90
+ absDn = absDn.minus(new this.DecimalClass(val).times(accDigit));
91
+ if (absDn.isZero())
92
+ break;
93
+ }
94
+ }
95
+ if (!absDn.isZero()) {
96
+ const val = isNegative ? absDn.neg() : absDn;
97
+ result.push({
98
+ num: val.toNumber(),
99
+ decimal: val,
100
+ unit: this.unitNames[0],
101
+ numStr: this.formatNumber(val, this.fractionDigits),
102
+ });
103
+ }
104
+ return result;
105
+ }
106
+ // 将数字格式化为链式单位字符串
107
+ /**
108
+ * Formats a number as a chain of units string
109
+ *
110
+ * @param num - The input number to format
111
+ * @returns The formatted chain string
112
+ */
113
+ formatChain(num, separator = this.separator) {
114
+ const chain = this.getChainUnit(num);
115
+ return chain
116
+ .map(({ numStr, unit }) => `${numStr}${this.convert ? this.convert(unit) : unit}`)
117
+ .join(separator);
118
+ }
119
+ // 将给定数值从指定单位转换为基本单位
120
+ /**
121
+ * Converts a value from the specified unit to the base unit
122
+ *
123
+ * @param num - The number to convert
124
+ * @param unit - The original unit of the number
125
+ * @returns The converted value in base unit
126
+ */
127
+ toBase(num, unit) {
128
+ if (Number.isNaN(num))
129
+ throw new Error(utils.ERROR_NAN_INPUT);
130
+ const unitDigitsLen = this.unitDigits.length;
131
+ let dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
132
+ for (let i = 0; i < unitDigitsLen; i++) {
133
+ const digit = this.unitDigits[i];
134
+ if (this.unitNames[i] === unit) {
135
+ return dn;
136
+ }
137
+ dn = dn.times(digit);
138
+ }
139
+ if (unit === this.unitNames.at(-1)) {
140
+ return dn;
141
+ }
142
+ throw new Error(`Undefined unit: "${unit}".`);
143
+ }
144
+ // 从给定字符串中分离出数字部分和单位
145
+ /**
146
+ * Splits a string into its numeric part and unit
147
+ *
148
+ * @param str - Input string containing a number followed by a unit
149
+ * @returns An object containing the numeric value, unit, and Decimal instance
150
+ * @throws An error if no predefined unit is matched
151
+ */
152
+ splitUnit(str) {
153
+ const { num, unit, numStr } = super.splitUnit(str);
154
+ return {
155
+ num,
156
+ decimal: new this.DecimalClass(numStr),
157
+ unit,
158
+ numStr,
159
+ };
160
+ }
161
+ // 将带单位的值转换为基础单位的数值
162
+ /**
163
+ * Parses a string with unit into a base unit numeric value
164
+ *
165
+ * @param str - Input string containing a number and unit
166
+ * @returns The value converted to base unit
167
+ */
168
+ parse(str) {
169
+ const { decimal, unit } = this.splitUnit(str);
170
+ return this.toBase(decimal, unit);
171
+ }
172
+ // 将给定数值从原单位转换为最佳单位,并可指定小数精度
173
+ /**
174
+ * Converts a value from the original unit to the optimal unit with optional decimal precision
175
+ *
176
+ * @param num - The number to convert
177
+ * @param unit - The original unit
178
+ * @param fractionDigits - Optional decimal places for formatting output
179
+ * @returns The converted number as a formatted string
180
+ */
181
+ fromUnitFormat(num, unit, fractionDigits) {
182
+ const nnum = this.toBase(num, unit);
183
+ return this.format(nnum, fractionDigits);
184
+ }
185
+ }
186
+
187
+ /*!
188
+ * smart-unit
189
+ * Copyright (c) [2026] [flycran]
190
+ * MIT License. See LICENSE for details.
191
+ */
192
+
193
+ exports.ERROR_NAN_INPUT = utils.ERROR_NAN_INPUT;
194
+ exports.SmartUnitPrecision = SmartUnitPrecision;
195
+ exports.default = SmartUnitPrecision;
@@ -0,0 +1,9 @@
1
+ /*!
2
+ * smart-unit
3
+ * Copyright (c) [2026] [flycran]
4
+ * MIT License. See LICENSE for details.
5
+ */
6
+ export * from './SmartUnitPrecision';
7
+ export * from './utils';
8
+ import { SmartUnitPrecision } from './SmartUnitPrecision';
9
+ export default SmartUnitPrecision;
@@ -0,0 +1,189 @@
1
+ import DecimalConstructor from 'decimal.js';
2
+ import { S as SmartUnitBase, E as ERROR_NAN_INPUT } from './utils-C1byK7Uk.js';
3
+
4
+ class SmartUnitPrecision extends SmartUnitBase {
5
+ constructor(units, option = {}) {
6
+ super(units, option);
7
+ this.DecimalClass = DecimalConstructor;
8
+ if (option.decimalOptions) {
9
+ this.DecimalClass = DecimalConstructor.clone(option.decimalOptions);
10
+ }
11
+ }
12
+ // 根据输入数值获取单位和调整后的值
13
+ /**
14
+ * Gets the appropriate unit and adjusted value for the input number
15
+ *
16
+ * @param num - The input NumPrecision to determine the unit for
17
+ * @param fractionDigits - Decimal precision configuration
18
+ * @returns The FormattedValue object containing the number, unit, and decimal instance
19
+ */
20
+ getUnit(num) {
21
+ if (Number.isNaN(num))
22
+ throw new Error(ERROR_NAN_INPUT);
23
+ const unitDigitsLen = this.unitDigits.length;
24
+ const dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
25
+ const isNegative = dn.isNegative();
26
+ let absDn = isNegative ? dn.abs() : dn;
27
+ let i = 0;
28
+ while (i < unitDigitsLen) {
29
+ const digit = this.unitDigits[i];
30
+ if (absDn.lt(digit * this.threshold)) {
31
+ break;
32
+ }
33
+ absDn = absDn.dividedBy(digit);
34
+ i++;
35
+ }
36
+ const result = isNegative ? absDn.neg() : absDn;
37
+ const n = result.toNumber();
38
+ return {
39
+ num: n,
40
+ decimal: result,
41
+ unit: this.unitNames[i],
42
+ numStr: this.formatNumber(result, this.fractionDigits),
43
+ };
44
+ }
45
+ // 将数字转换为字符串表示形式,并可选择配置小数位数
46
+ /**
47
+ * Formats a number as a string with unit and optional decimal place configuration
48
+ *
49
+ * @param num - The input number to format
50
+ * @param fractionDigits - Decimal precision configuration
51
+ * @returns The formatted string with number and unit
52
+ */
53
+ format(num, fractionDigits = this.fractionDigits) {
54
+ const { decimal, unit } = this.getUnit(num);
55
+ const formatted = this.formatNumber(decimal, fractionDigits);
56
+ return `${formatted}${this.convert ? this.convert(unit) : unit}`;
57
+ }
58
+ // 根据输入数值获取链式单位数组
59
+ /**
60
+ * Gets the chain of units for the input number
61
+ *
62
+ * @param num - The input number to determine the chain for
63
+ * @returns An array of FormattedValue objects representing the chain of units
64
+ */
65
+ getChainUnit(num) {
66
+ if (Number.isNaN(num))
67
+ throw new Error(ERROR_NAN_INPUT);
68
+ const result = [];
69
+ if (num === 0) {
70
+ return [{ num: 0, unit: this.unitNames[0], numStr: '0', decimal: new this.DecimalClass(0) }];
71
+ }
72
+ const dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
73
+ const isNegative = dn.isNegative();
74
+ let absDn = isNegative ? dn.abs() : dn;
75
+ for (let i = this.accumulatedDigits.length - 1; i >= 0; i--) {
76
+ const accDigit = this.accumulatedDigits[i];
77
+ if (absDn.gte(accDigit)) {
78
+ const res = absDn.dividedToIntegerBy(accDigit);
79
+ const val = isNegative ? res.neg() : res;
80
+ result.push({
81
+ num: val.toNumber(),
82
+ decimal: new this.DecimalClass(val),
83
+ unit: this.unitNames[i + 1],
84
+ numStr: this.formatNumber(val, this.fractionDigits),
85
+ });
86
+ absDn = absDn.minus(new this.DecimalClass(val).times(accDigit));
87
+ if (absDn.isZero())
88
+ break;
89
+ }
90
+ }
91
+ if (!absDn.isZero()) {
92
+ const val = isNegative ? absDn.neg() : absDn;
93
+ result.push({
94
+ num: val.toNumber(),
95
+ decimal: val,
96
+ unit: this.unitNames[0],
97
+ numStr: this.formatNumber(val, this.fractionDigits),
98
+ });
99
+ }
100
+ return result;
101
+ }
102
+ // 将数字格式化为链式单位字符串
103
+ /**
104
+ * Formats a number as a chain of units string
105
+ *
106
+ * @param num - The input number to format
107
+ * @returns The formatted chain string
108
+ */
109
+ formatChain(num, separator = this.separator) {
110
+ const chain = this.getChainUnit(num);
111
+ return chain
112
+ .map(({ numStr, unit }) => `${numStr}${this.convert ? this.convert(unit) : unit}`)
113
+ .join(separator);
114
+ }
115
+ // 将给定数值从指定单位转换为基本单位
116
+ /**
117
+ * Converts a value from the specified unit to the base unit
118
+ *
119
+ * @param num - The number to convert
120
+ * @param unit - The original unit of the number
121
+ * @returns The converted value in base unit
122
+ */
123
+ toBase(num, unit) {
124
+ if (Number.isNaN(num))
125
+ throw new Error(ERROR_NAN_INPUT);
126
+ const unitDigitsLen = this.unitDigits.length;
127
+ let dn = new this.DecimalClass(typeof num === 'bigint' ? num.toString() : num);
128
+ for (let i = 0; i < unitDigitsLen; i++) {
129
+ const digit = this.unitDigits[i];
130
+ if (this.unitNames[i] === unit) {
131
+ return dn;
132
+ }
133
+ dn = dn.times(digit);
134
+ }
135
+ if (unit === this.unitNames.at(-1)) {
136
+ return dn;
137
+ }
138
+ throw new Error(`Undefined unit: "${unit}".`);
139
+ }
140
+ // 从给定字符串中分离出数字部分和单位
141
+ /**
142
+ * Splits a string into its numeric part and unit
143
+ *
144
+ * @param str - Input string containing a number followed by a unit
145
+ * @returns An object containing the numeric value, unit, and Decimal instance
146
+ * @throws An error if no predefined unit is matched
147
+ */
148
+ splitUnit(str) {
149
+ const { num, unit, numStr } = super.splitUnit(str);
150
+ return {
151
+ num,
152
+ decimal: new this.DecimalClass(numStr),
153
+ unit,
154
+ numStr,
155
+ };
156
+ }
157
+ // 将带单位的值转换为基础单位的数值
158
+ /**
159
+ * Parses a string with unit into a base unit numeric value
160
+ *
161
+ * @param str - Input string containing a number and unit
162
+ * @returns The value converted to base unit
163
+ */
164
+ parse(str) {
165
+ const { decimal, unit } = this.splitUnit(str);
166
+ return this.toBase(decimal, unit);
167
+ }
168
+ // 将给定数值从原单位转换为最佳单位,并可指定小数精度
169
+ /**
170
+ * Converts a value from the original unit to the optimal unit with optional decimal precision
171
+ *
172
+ * @param num - The number to convert
173
+ * @param unit - The original unit
174
+ * @param fractionDigits - Optional decimal places for formatting output
175
+ * @returns The converted number as a formatted string
176
+ */
177
+ fromUnitFormat(num, unit, fractionDigits) {
178
+ const nnum = this.toBase(num, unit);
179
+ return this.format(nnum, fractionDigits);
180
+ }
181
+ }
182
+
183
+ /*!
184
+ * smart-unit
185
+ * Copyright (c) [2026] [flycran]
186
+ * MIT License. See LICENSE for details.
187
+ */
188
+
189
+ export { ERROR_NAN_INPUT, SmartUnitPrecision, SmartUnitPrecision as default };
@@ -0,0 +1,146 @@
1
+ class SmartUnitBase {
2
+ /** Accumulated digits for unit conversion */
3
+ get accumulatedDigits() {
4
+ if (!this._accumulatedDigits)
5
+ this.createAccumulatedDigits();
6
+ return this._accumulatedDigits;
7
+ }
8
+ /** Sorted unit names by length for efficient lookup */
9
+ get sortedUnitNames() {
10
+ if (!this._sortedUnitNames)
11
+ this.createSortedUnitNames();
12
+ return this._sortedUnitNames;
13
+ }
14
+ constructor(units, option = {}) {
15
+ this.unitNames = [];
16
+ this.unitDigits = [];
17
+ // Initialize
18
+ if (!units.length)
19
+ throw new Error('units is empty.');
20
+ this.threshold = option.threshold || 1;
21
+ this.fractionDigits = option.fractionDigits;
22
+ this.separator = option.separator || '';
23
+ if (option.baseDigit) {
24
+ for (let i = 0; i < units.length; i++) {
25
+ const name = units[i];
26
+ if (typeof name !== 'string')
27
+ throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of string type.`);
28
+ }
29
+ this.unitNames = units;
30
+ this.unitDigits = Array(units.length - 1).fill(option.baseDigit);
31
+ }
32
+ else {
33
+ for (let i = 1; i < units.length; i += 2) {
34
+ const digit = units[i];
35
+ if (typeof digit !== 'number')
36
+ throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
37
+ this.unitDigits.push(units[i]);
38
+ const name = units[i - 1];
39
+ if (typeof name !== 'string')
40
+ throw new Error(`The unit setting is incorrect; the element at index [${i - 1}] should be of string type.`);
41
+ this.unitNames.push(name);
42
+ }
43
+ this.unitNames.push(units[units.length - 1]);
44
+ }
45
+ }
46
+ withConvert(convert) {
47
+ const su = Object.create(this);
48
+ su.convert = convert;
49
+ return su;
50
+ }
51
+ // 累积比例
52
+ createAccumulatedDigits() {
53
+ const accumulatedDigits = [];
54
+ this.unitDigits.forEach((digit, index) => {
55
+ if (index === 0) {
56
+ accumulatedDigits.push(digit);
57
+ }
58
+ else {
59
+ accumulatedDigits.push(accumulatedDigits[index - 1] * digit);
60
+ }
61
+ });
62
+ this._accumulatedDigits = accumulatedDigits;
63
+ }
64
+ // 长度排序后的单位名称
65
+ createSortedUnitNames() {
66
+ const sortedUnits = [...this.unitNames].sort((a, b) => b.length - a.length);
67
+ this._sortedUnitNames = sortedUnits;
68
+ }
69
+ // 格式化数字的小数位数
70
+ /**
71
+ * Formats the decimal places of a number
72
+ *
73
+ * @param value - The value to format
74
+ * @param fractionDigits - Decimal precision configuration
75
+ * @returns The formatted string representation of the number
76
+ */
77
+ formatNumber(value, fractionDigits = this.fractionDigits) {
78
+ if (typeof fractionDigits === 'number') {
79
+ return value.toFixed(fractionDigits);
80
+ }
81
+ else if (typeof fractionDigits === 'string') {
82
+ const [dp1, dp2] = fractionDigits.split('-');
83
+ const ndp = (value.toString().split('.')[1] || '').length;
84
+ const minDp = dp1 ? +dp1 : -Infinity;
85
+ const maxDp = dp2 ? +dp2 : Infinity;
86
+ if (ndp < minDp) {
87
+ return value.toFixed(minDp);
88
+ }
89
+ else if (ndp > maxDp) {
90
+ return value.toFixed(maxDp);
91
+ }
92
+ else {
93
+ return value.toString();
94
+ }
95
+ }
96
+ else {
97
+ return value.toString();
98
+ }
99
+ }
100
+ // format抽象方法
101
+ _format(numStr, unit) {
102
+ return `${numStr}${this.convert ? this.convert(unit) : unit}`;
103
+ }
104
+ _formatChain(chain, separator = this.separator) {
105
+ return chain.map(({ numStr, unit }) => this._format(numStr, unit)).join(separator);
106
+ }
107
+ // 将数字格式化为链式单位字符串
108
+ /**
109
+ * Formats a number as a chain of units string
110
+ * @param num - The input number to format
111
+ * @returns The formatted chain string
112
+ */
113
+ formatChain(num, separator = this.separator) {
114
+ const chain = this.getChainUnit(num);
115
+ return this._formatChain(chain, separator);
116
+ }
117
+ // 从给定字符串中分离出数字部分和单位
118
+ /**
119
+ * Splits a string into its numeric part and unit
120
+ *
121
+ * @param str - Input string containing a number followed by a unit
122
+ * @returns An object containing the numeric value, unit, and Decimal instance
123
+ * @throws An error if no predefined unit is matched
124
+ */
125
+ splitUnit(str) {
126
+ const sortedUnits = this.sortedUnitNames;
127
+ for (const unit of sortedUnits) {
128
+ if (str.endsWith(unit)) {
129
+ const numStr = str.slice(0, -unit.length);
130
+ const num = +numStr;
131
+ if (Number.isNaN(num))
132
+ throw new Error(`Invalid number: "${numStr}".`);
133
+ return {
134
+ num,
135
+ unit,
136
+ numStr,
137
+ };
138
+ }
139
+ }
140
+ throw new Error(`Undefined unit: "${str}".`);
141
+ }
142
+ }
143
+
144
+ const ERROR_NAN_INPUT = 'Accepting NaN as an argument may be unintentional and could lead to invalid results.';
145
+
146
+ export { ERROR_NAN_INPUT as E, SmartUnitBase as S };
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ class SmartUnitBase {
4
+ /** Accumulated digits for unit conversion */
5
+ get accumulatedDigits() {
6
+ if (!this._accumulatedDigits)
7
+ this.createAccumulatedDigits();
8
+ return this._accumulatedDigits;
9
+ }
10
+ /** Sorted unit names by length for efficient lookup */
11
+ get sortedUnitNames() {
12
+ if (!this._sortedUnitNames)
13
+ this.createSortedUnitNames();
14
+ return this._sortedUnitNames;
15
+ }
16
+ constructor(units, option = {}) {
17
+ this.unitNames = [];
18
+ this.unitDigits = [];
19
+ // Initialize
20
+ if (!units.length)
21
+ throw new Error('units is empty.');
22
+ this.threshold = option.threshold || 1;
23
+ this.fractionDigits = option.fractionDigits;
24
+ this.separator = option.separator || '';
25
+ if (option.baseDigit) {
26
+ for (let i = 0; i < units.length; i++) {
27
+ const name = units[i];
28
+ if (typeof name !== 'string')
29
+ throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of string type.`);
30
+ }
31
+ this.unitNames = units;
32
+ this.unitDigits = Array(units.length - 1).fill(option.baseDigit);
33
+ }
34
+ else {
35
+ for (let i = 1; i < units.length; i += 2) {
36
+ const digit = units[i];
37
+ if (typeof digit !== 'number')
38
+ throw new Error(`The unit setting is incorrect; the element at index [${i}] should be of numeric type.`);
39
+ this.unitDigits.push(units[i]);
40
+ const name = units[i - 1];
41
+ if (typeof name !== 'string')
42
+ throw new Error(`The unit setting is incorrect; the element at index [${i - 1}] should be of string type.`);
43
+ this.unitNames.push(name);
44
+ }
45
+ this.unitNames.push(units[units.length - 1]);
46
+ }
47
+ }
48
+ withConvert(convert) {
49
+ const su = Object.create(this);
50
+ su.convert = convert;
51
+ return su;
52
+ }
53
+ // 累积比例
54
+ createAccumulatedDigits() {
55
+ const accumulatedDigits = [];
56
+ this.unitDigits.forEach((digit, index) => {
57
+ if (index === 0) {
58
+ accumulatedDigits.push(digit);
59
+ }
60
+ else {
61
+ accumulatedDigits.push(accumulatedDigits[index - 1] * digit);
62
+ }
63
+ });
64
+ this._accumulatedDigits = accumulatedDigits;
65
+ }
66
+ // 长度排序后的单位名称
67
+ createSortedUnitNames() {
68
+ const sortedUnits = [...this.unitNames].sort((a, b) => b.length - a.length);
69
+ this._sortedUnitNames = sortedUnits;
70
+ }
71
+ // 格式化数字的小数位数
72
+ /**
73
+ * Formats the decimal places of a number
74
+ *
75
+ * @param value - The value to format
76
+ * @param fractionDigits - Decimal precision configuration
77
+ * @returns The formatted string representation of the number
78
+ */
79
+ formatNumber(value, fractionDigits = this.fractionDigits) {
80
+ if (typeof fractionDigits === 'number') {
81
+ return value.toFixed(fractionDigits);
82
+ }
83
+ else if (typeof fractionDigits === 'string') {
84
+ const [dp1, dp2] = fractionDigits.split('-');
85
+ const ndp = (value.toString().split('.')[1] || '').length;
86
+ const minDp = dp1 ? +dp1 : -Infinity;
87
+ const maxDp = dp2 ? +dp2 : Infinity;
88
+ if (ndp < minDp) {
89
+ return value.toFixed(minDp);
90
+ }
91
+ else if (ndp > maxDp) {
92
+ return value.toFixed(maxDp);
93
+ }
94
+ else {
95
+ return value.toString();
96
+ }
97
+ }
98
+ else {
99
+ return value.toString();
100
+ }
101
+ }
102
+ // format抽象方法
103
+ _format(numStr, unit) {
104
+ return `${numStr}${this.convert ? this.convert(unit) : unit}`;
105
+ }
106
+ _formatChain(chain, separator = this.separator) {
107
+ return chain.map(({ numStr, unit }) => this._format(numStr, unit)).join(separator);
108
+ }
109
+ // 将数字格式化为链式单位字符串
110
+ /**
111
+ * Formats a number as a chain of units string
112
+ * @param num - The input number to format
113
+ * @returns The formatted chain string
114
+ */
115
+ formatChain(num, separator = this.separator) {
116
+ const chain = this.getChainUnit(num);
117
+ return this._formatChain(chain, separator);
118
+ }
119
+ // 从给定字符串中分离出数字部分和单位
120
+ /**
121
+ * Splits a string into its numeric part and unit
122
+ *
123
+ * @param str - Input string containing a number followed by a unit
124
+ * @returns An object containing the numeric value, unit, and Decimal instance
125
+ * @throws An error if no predefined unit is matched
126
+ */
127
+ splitUnit(str) {
128
+ const sortedUnits = this.sortedUnitNames;
129
+ for (const unit of sortedUnits) {
130
+ if (str.endsWith(unit)) {
131
+ const numStr = str.slice(0, -unit.length);
132
+ const num = +numStr;
133
+ if (Number.isNaN(num))
134
+ throw new Error(`Invalid number: "${numStr}".`);
135
+ return {
136
+ num,
137
+ unit,
138
+ numStr,
139
+ };
140
+ }
141
+ }
142
+ throw new Error(`Undefined unit: "${str}".`);
143
+ }
144
+ }
145
+
146
+ const ERROR_NAN_INPUT = 'Accepting NaN as an argument may be unintentional and could lead to invalid results.';
147
+
148
+ exports.ERROR_NAN_INPUT = ERROR_NAN_INPUT;
149
+ exports.SmartUnitBase = SmartUnitBase;