@qrwise/pos-calculations 0.0.16 → 0.0.18
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/dist/index.cjs +108 -0
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +108 -0
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -61,7 +61,114 @@ function getDiscountBreakdown(discountType, discountedAmount) {
|
|
|
61
61
|
mov: includesAny(value, ["uniformed", "uniformed personnel", "mov"]) ? discountedAmount : 0
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
var splitDiscountTypes = [
|
|
65
|
+
{ type: "SENIOR", count: "seniorCount", breakdown: "sc", vatExempt: true },
|
|
66
|
+
{ type: "PWD", count: "pwdCount", breakdown: "pwd", vatExempt: true },
|
|
67
|
+
{ type: "NAAC", count: "naacCount", breakdown: "naac", vatExempt: false },
|
|
68
|
+
{ type: "MOV", count: "movCount", breakdown: "mov", vatExempt: false },
|
|
69
|
+
{ type: "SOLO", count: "soloParentCount", breakdown: "solo", vatExempt: false }
|
|
70
|
+
];
|
|
71
|
+
function normalizedCount(value) {
|
|
72
|
+
return Math.max(0, Math.floor(toMoneyNumber(value)));
|
|
73
|
+
}
|
|
74
|
+
function calculateSplitTotals(input) {
|
|
75
|
+
if (!input.paxDiscountCounts) return null;
|
|
76
|
+
const counts = input.paxDiscountCounts;
|
|
77
|
+
const regularCount = normalizedCount(counts.regularCount);
|
|
78
|
+
const concessionCount = splitDiscountTypes.reduce((total, item) => total + normalizedCount(counts[item.count]), 0);
|
|
79
|
+
const paxCount = regularCount + concessionCount;
|
|
80
|
+
if (paxCount === 0) return null;
|
|
81
|
+
const vatDivisor = Number(input.vatRate || 0) / 100;
|
|
82
|
+
const vatRate = Math.max(0, vatDivisor - 1);
|
|
83
|
+
const scRate = Number(input.serviceChargeRate || 0) / 100;
|
|
84
|
+
const discountableAmount = Math.max(0, toMoneyNumber(input.discountableTotalAmount));
|
|
85
|
+
const nonDiscountableAmount = Math.max(0, toMoneyNumber(input.nonDiscountableTotalAmount));
|
|
86
|
+
const totalOrderAmount = discountableAmount + nonDiscountableAmount;
|
|
87
|
+
const voucherRate = input.voucherType === "FIXED" ? input.voucherRate : Number(input.voucherRate || 0) / 100;
|
|
88
|
+
let voucherDiscounted = 0;
|
|
89
|
+
if (voucherRate > 0) {
|
|
90
|
+
voucherDiscounted = input.voucherType === "FIXED" ? -format2(Math.min(toMoneyNumber(voucherRate), totalOrderAmount)) : -format2(totalOrderAmount * voucherRate);
|
|
91
|
+
}
|
|
92
|
+
const subtotal = format2(totalOrderAmount + voucherDiscounted);
|
|
93
|
+
const discountableSubtotal = Math.max(0, discountableAmount - Math.abs(voucherDiscounted));
|
|
94
|
+
const nonDiscountableSubtotal = Math.max(0, subtotal - discountableSubtotal);
|
|
95
|
+
const discountableShare = discountableSubtotal / paxCount;
|
|
96
|
+
const discountBreakdown = { sc: 0, pwd: 0, solo: 0, naac: 0, mov: 0 };
|
|
97
|
+
let vatSales = (nonDiscountableSubtotal + discountableShare * regularCount) / vatDivisor;
|
|
98
|
+
let vatExemptSales = 0;
|
|
99
|
+
let totalDiscount = 0;
|
|
100
|
+
for (const item of splitDiscountTypes) {
|
|
101
|
+
const count = normalizedCount(counts[item.count]);
|
|
102
|
+
if (count === 0) continue;
|
|
103
|
+
const netShare = discountableShare * count / vatDivisor;
|
|
104
|
+
const rate = Number(input.discountRates?.[item.type] ?? input.discountRate ?? 0) / 100;
|
|
105
|
+
const discount = format2(netShare * Math.max(0, rate));
|
|
106
|
+
if (item.vatExempt) vatExemptSales += netShare;
|
|
107
|
+
else vatSales += netShare;
|
|
108
|
+
discountBreakdown[item.breakdown] = -discount;
|
|
109
|
+
totalDiscount += discount;
|
|
110
|
+
}
|
|
111
|
+
vatSales = format2(vatSales);
|
|
112
|
+
vatExemptSales = format2(vatExemptSales);
|
|
113
|
+
const discounted = -format2(totalDiscount);
|
|
114
|
+
const vat = format2(vatSales * vatRate);
|
|
115
|
+
const vatNet = format2(vatSales + vatExemptSales + discounted);
|
|
116
|
+
const serviceChargeBase = Math.min(Math.max(0, toMoneyNumber(input.serviceChargeableTotalAmount)), subtotal);
|
|
117
|
+
const serviceCharge = input.serviceChargeRate > 0 ? format2(serviceChargeBase / vatDivisor * scRate) : 0;
|
|
118
|
+
const togoCharge = input.togoableTotalAmount > 0 ? input.togoCharge : 0;
|
|
119
|
+
const totalAmount = format2(Math.max(0, vatNet + vat + serviceCharge + togoCharge));
|
|
120
|
+
const voucherVatNet = format2(totalOrderAmount / vatDivisor);
|
|
121
|
+
const voucherVat = format2(voucherVatNet * vatRate);
|
|
122
|
+
return {
|
|
123
|
+
quantity: input.quantity,
|
|
124
|
+
subtotal,
|
|
125
|
+
isAddVat: splitDiscountTypes.some((item) => !item.vatExempt && normalizedCount(counts[item.count]) > 0),
|
|
126
|
+
vatNet,
|
|
127
|
+
vat,
|
|
128
|
+
discounted,
|
|
129
|
+
discountBreakdown,
|
|
130
|
+
voucherDiscounted,
|
|
131
|
+
serviceCharge,
|
|
132
|
+
togoCharge,
|
|
133
|
+
totalAmount,
|
|
134
|
+
receipt: {
|
|
135
|
+
gross: totalOrderAmount,
|
|
136
|
+
hasVoucher: voucherRate > 0,
|
|
137
|
+
voucher: {
|
|
138
|
+
discount: voucherDiscounted,
|
|
139
|
+
net: subtotal,
|
|
140
|
+
vatNet: voucherVatNet,
|
|
141
|
+
vat: voucherVat,
|
|
142
|
+
forBirDiscount: -(input.voucherType === "FIXED" ? voucherVatNet - Number(voucherRate.toFixed(2)) : voucherVatNet * Number(voucherRate.toFixed(2)))
|
|
143
|
+
},
|
|
144
|
+
hasDiscount: totalDiscount > 0,
|
|
145
|
+
discount: {
|
|
146
|
+
discount: discounted,
|
|
147
|
+
net: vatNet
|
|
148
|
+
},
|
|
149
|
+
netOfVat: format2(vatSales + vatExemptSales),
|
|
150
|
+
vat,
|
|
151
|
+
serviceCharge,
|
|
152
|
+
togoCharge,
|
|
153
|
+
totalAmount,
|
|
154
|
+
bir: {
|
|
155
|
+
vatSales,
|
|
156
|
+
vatExemptSales,
|
|
157
|
+
vatZeroRatedSales: 0,
|
|
158
|
+
nonTaxableSales: 0,
|
|
159
|
+
vat,
|
|
160
|
+
totalSales: subtotal,
|
|
161
|
+
discount: discounted,
|
|
162
|
+
serviceCharge,
|
|
163
|
+
togoCharge,
|
|
164
|
+
amountPayable: totalAmount
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
64
169
|
function calculateTotals(input) {
|
|
170
|
+
const splitTotals = calculateSplitTotals(input);
|
|
171
|
+
if (splitTotals) return splitTotals;
|
|
65
172
|
const vatRate = Number(input.vatRate || 0) / 100;
|
|
66
173
|
const scRate = Number(input.serviceChargeRate || 0) / 100;
|
|
67
174
|
const discountRate = Number(input.discountRate || 0) / 100;
|
|
@@ -110,6 +217,7 @@ function calculateTotals(input) {
|
|
|
110
217
|
vatNet,
|
|
111
218
|
vat,
|
|
112
219
|
discounted,
|
|
220
|
+
discountBreakdown: getDiscountBreakdown(input.discountType, discounted),
|
|
113
221
|
voucherDiscounted,
|
|
114
222
|
serviceCharge,
|
|
115
223
|
togoCharge,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
type VoucherType = "FIXED" | "PERCENTAGE";
|
|
2
2
|
type DiscountType = "SENIOR" | "PWD" | "NAAC" | "SOLO" | "MOV";
|
|
3
|
+
type DiscountRates = Partial<Record<DiscountType, number>>;
|
|
4
|
+
interface PaxDiscountCounts {
|
|
5
|
+
seniorCount: number;
|
|
6
|
+
pwdCount: number;
|
|
7
|
+
naacCount: number;
|
|
8
|
+
movCount: number;
|
|
9
|
+
soloParentCount: number;
|
|
10
|
+
regularCount: number;
|
|
11
|
+
}
|
|
12
|
+
interface DiscountBreakdown {
|
|
13
|
+
sc: number;
|
|
14
|
+
pwd: number;
|
|
15
|
+
solo: number;
|
|
16
|
+
naac: number;
|
|
17
|
+
mov: number;
|
|
18
|
+
}
|
|
3
19
|
interface CalculateTotalsInput {
|
|
4
20
|
quantity: number;
|
|
5
21
|
discountableTotalAmount: number;
|
|
@@ -10,6 +26,12 @@ interface CalculateTotalsInput {
|
|
|
10
26
|
voucherRate: number;
|
|
11
27
|
discountType: DiscountType | null;
|
|
12
28
|
discountRate: number;
|
|
29
|
+
discountRates?: DiscountRates;
|
|
30
|
+
/**
|
|
31
|
+
* When supplied, the discountable amount is split evenly across these pax
|
|
32
|
+
* counts and each concession type is calculated independently.
|
|
33
|
+
*/
|
|
34
|
+
paxDiscountCounts?: PaxDiscountCounts;
|
|
13
35
|
vatRate: number;
|
|
14
36
|
serviceChargeRate: number;
|
|
15
37
|
togoCharge: number;
|
|
@@ -21,6 +43,7 @@ interface CalculateTotalsResult {
|
|
|
21
43
|
vatNet: number;
|
|
22
44
|
vat: number;
|
|
23
45
|
discounted: number;
|
|
46
|
+
discountBreakdown: DiscountBreakdown;
|
|
24
47
|
voucherDiscounted: number;
|
|
25
48
|
serviceCharge: number;
|
|
26
49
|
togoCharge: number;
|
|
@@ -74,4 +97,4 @@ declare function getDiscountBreakdown(discountType: string | null | undefined, d
|
|
|
74
97
|
};
|
|
75
98
|
declare function calculateTotals(input: CalculateTotalsInput): CalculateTotalsResult;
|
|
76
99
|
|
|
77
|
-
export { type CalculateTotalsInput, type CalculateTotalsResult, type DiscountType, type VoucherType, calculateTotals, clamp, format2, getDiscountBreakdown, isAddVatAfterDiscount, isVatExemptDiscount, toMoneyNumber };
|
|
100
|
+
export { type CalculateTotalsInput, type CalculateTotalsResult, type DiscountBreakdown, type DiscountRates, type DiscountType, type PaxDiscountCounts, type VoucherType, calculateTotals, clamp, format2, getDiscountBreakdown, isAddVatAfterDiscount, isVatExemptDiscount, toMoneyNumber };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
type VoucherType = "FIXED" | "PERCENTAGE";
|
|
2
2
|
type DiscountType = "SENIOR" | "PWD" | "NAAC" | "SOLO" | "MOV";
|
|
3
|
+
type DiscountRates = Partial<Record<DiscountType, number>>;
|
|
4
|
+
interface PaxDiscountCounts {
|
|
5
|
+
seniorCount: number;
|
|
6
|
+
pwdCount: number;
|
|
7
|
+
naacCount: number;
|
|
8
|
+
movCount: number;
|
|
9
|
+
soloParentCount: number;
|
|
10
|
+
regularCount: number;
|
|
11
|
+
}
|
|
12
|
+
interface DiscountBreakdown {
|
|
13
|
+
sc: number;
|
|
14
|
+
pwd: number;
|
|
15
|
+
solo: number;
|
|
16
|
+
naac: number;
|
|
17
|
+
mov: number;
|
|
18
|
+
}
|
|
3
19
|
interface CalculateTotalsInput {
|
|
4
20
|
quantity: number;
|
|
5
21
|
discountableTotalAmount: number;
|
|
@@ -10,6 +26,12 @@ interface CalculateTotalsInput {
|
|
|
10
26
|
voucherRate: number;
|
|
11
27
|
discountType: DiscountType | null;
|
|
12
28
|
discountRate: number;
|
|
29
|
+
discountRates?: DiscountRates;
|
|
30
|
+
/**
|
|
31
|
+
* When supplied, the discountable amount is split evenly across these pax
|
|
32
|
+
* counts and each concession type is calculated independently.
|
|
33
|
+
*/
|
|
34
|
+
paxDiscountCounts?: PaxDiscountCounts;
|
|
13
35
|
vatRate: number;
|
|
14
36
|
serviceChargeRate: number;
|
|
15
37
|
togoCharge: number;
|
|
@@ -21,6 +43,7 @@ interface CalculateTotalsResult {
|
|
|
21
43
|
vatNet: number;
|
|
22
44
|
vat: number;
|
|
23
45
|
discounted: number;
|
|
46
|
+
discountBreakdown: DiscountBreakdown;
|
|
24
47
|
voucherDiscounted: number;
|
|
25
48
|
serviceCharge: number;
|
|
26
49
|
togoCharge: number;
|
|
@@ -74,4 +97,4 @@ declare function getDiscountBreakdown(discountType: string | null | undefined, d
|
|
|
74
97
|
};
|
|
75
98
|
declare function calculateTotals(input: CalculateTotalsInput): CalculateTotalsResult;
|
|
76
99
|
|
|
77
|
-
export { type CalculateTotalsInput, type CalculateTotalsResult, type DiscountType, type VoucherType, calculateTotals, clamp, format2, getDiscountBreakdown, isAddVatAfterDiscount, isVatExemptDiscount, toMoneyNumber };
|
|
100
|
+
export { type CalculateTotalsInput, type CalculateTotalsResult, type DiscountBreakdown, type DiscountRates, type DiscountType, type PaxDiscountCounts, type VoucherType, calculateTotals, clamp, format2, getDiscountBreakdown, isAddVatAfterDiscount, isVatExemptDiscount, toMoneyNumber };
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,114 @@ function getDiscountBreakdown(discountType, discountedAmount) {
|
|
|
29
29
|
mov: includesAny(value, ["uniformed", "uniformed personnel", "mov"]) ? discountedAmount : 0
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
+
var splitDiscountTypes = [
|
|
33
|
+
{ type: "SENIOR", count: "seniorCount", breakdown: "sc", vatExempt: true },
|
|
34
|
+
{ type: "PWD", count: "pwdCount", breakdown: "pwd", vatExempt: true },
|
|
35
|
+
{ type: "NAAC", count: "naacCount", breakdown: "naac", vatExempt: false },
|
|
36
|
+
{ type: "MOV", count: "movCount", breakdown: "mov", vatExempt: false },
|
|
37
|
+
{ type: "SOLO", count: "soloParentCount", breakdown: "solo", vatExempt: false }
|
|
38
|
+
];
|
|
39
|
+
function normalizedCount(value) {
|
|
40
|
+
return Math.max(0, Math.floor(toMoneyNumber(value)));
|
|
41
|
+
}
|
|
42
|
+
function calculateSplitTotals(input) {
|
|
43
|
+
if (!input.paxDiscountCounts) return null;
|
|
44
|
+
const counts = input.paxDiscountCounts;
|
|
45
|
+
const regularCount = normalizedCount(counts.regularCount);
|
|
46
|
+
const concessionCount = splitDiscountTypes.reduce((total, item) => total + normalizedCount(counts[item.count]), 0);
|
|
47
|
+
const paxCount = regularCount + concessionCount;
|
|
48
|
+
if (paxCount === 0) return null;
|
|
49
|
+
const vatDivisor = Number(input.vatRate || 0) / 100;
|
|
50
|
+
const vatRate = Math.max(0, vatDivisor - 1);
|
|
51
|
+
const scRate = Number(input.serviceChargeRate || 0) / 100;
|
|
52
|
+
const discountableAmount = Math.max(0, toMoneyNumber(input.discountableTotalAmount));
|
|
53
|
+
const nonDiscountableAmount = Math.max(0, toMoneyNumber(input.nonDiscountableTotalAmount));
|
|
54
|
+
const totalOrderAmount = discountableAmount + nonDiscountableAmount;
|
|
55
|
+
const voucherRate = input.voucherType === "FIXED" ? input.voucherRate : Number(input.voucherRate || 0) / 100;
|
|
56
|
+
let voucherDiscounted = 0;
|
|
57
|
+
if (voucherRate > 0) {
|
|
58
|
+
voucherDiscounted = input.voucherType === "FIXED" ? -format2(Math.min(toMoneyNumber(voucherRate), totalOrderAmount)) : -format2(totalOrderAmount * voucherRate);
|
|
59
|
+
}
|
|
60
|
+
const subtotal = format2(totalOrderAmount + voucherDiscounted);
|
|
61
|
+
const discountableSubtotal = Math.max(0, discountableAmount - Math.abs(voucherDiscounted));
|
|
62
|
+
const nonDiscountableSubtotal = Math.max(0, subtotal - discountableSubtotal);
|
|
63
|
+
const discountableShare = discountableSubtotal / paxCount;
|
|
64
|
+
const discountBreakdown = { sc: 0, pwd: 0, solo: 0, naac: 0, mov: 0 };
|
|
65
|
+
let vatSales = (nonDiscountableSubtotal + discountableShare * regularCount) / vatDivisor;
|
|
66
|
+
let vatExemptSales = 0;
|
|
67
|
+
let totalDiscount = 0;
|
|
68
|
+
for (const item of splitDiscountTypes) {
|
|
69
|
+
const count = normalizedCount(counts[item.count]);
|
|
70
|
+
if (count === 0) continue;
|
|
71
|
+
const netShare = discountableShare * count / vatDivisor;
|
|
72
|
+
const rate = Number(input.discountRates?.[item.type] ?? input.discountRate ?? 0) / 100;
|
|
73
|
+
const discount = format2(netShare * Math.max(0, rate));
|
|
74
|
+
if (item.vatExempt) vatExemptSales += netShare;
|
|
75
|
+
else vatSales += netShare;
|
|
76
|
+
discountBreakdown[item.breakdown] = -discount;
|
|
77
|
+
totalDiscount += discount;
|
|
78
|
+
}
|
|
79
|
+
vatSales = format2(vatSales);
|
|
80
|
+
vatExemptSales = format2(vatExemptSales);
|
|
81
|
+
const discounted = -format2(totalDiscount);
|
|
82
|
+
const vat = format2(vatSales * vatRate);
|
|
83
|
+
const vatNet = format2(vatSales + vatExemptSales + discounted);
|
|
84
|
+
const serviceChargeBase = Math.min(Math.max(0, toMoneyNumber(input.serviceChargeableTotalAmount)), subtotal);
|
|
85
|
+
const serviceCharge = input.serviceChargeRate > 0 ? format2(serviceChargeBase / vatDivisor * scRate) : 0;
|
|
86
|
+
const togoCharge = input.togoableTotalAmount > 0 ? input.togoCharge : 0;
|
|
87
|
+
const totalAmount = format2(Math.max(0, vatNet + vat + serviceCharge + togoCharge));
|
|
88
|
+
const voucherVatNet = format2(totalOrderAmount / vatDivisor);
|
|
89
|
+
const voucherVat = format2(voucherVatNet * vatRate);
|
|
90
|
+
return {
|
|
91
|
+
quantity: input.quantity,
|
|
92
|
+
subtotal,
|
|
93
|
+
isAddVat: splitDiscountTypes.some((item) => !item.vatExempt && normalizedCount(counts[item.count]) > 0),
|
|
94
|
+
vatNet,
|
|
95
|
+
vat,
|
|
96
|
+
discounted,
|
|
97
|
+
discountBreakdown,
|
|
98
|
+
voucherDiscounted,
|
|
99
|
+
serviceCharge,
|
|
100
|
+
togoCharge,
|
|
101
|
+
totalAmount,
|
|
102
|
+
receipt: {
|
|
103
|
+
gross: totalOrderAmount,
|
|
104
|
+
hasVoucher: voucherRate > 0,
|
|
105
|
+
voucher: {
|
|
106
|
+
discount: voucherDiscounted,
|
|
107
|
+
net: subtotal,
|
|
108
|
+
vatNet: voucherVatNet,
|
|
109
|
+
vat: voucherVat,
|
|
110
|
+
forBirDiscount: -(input.voucherType === "FIXED" ? voucherVatNet - Number(voucherRate.toFixed(2)) : voucherVatNet * Number(voucherRate.toFixed(2)))
|
|
111
|
+
},
|
|
112
|
+
hasDiscount: totalDiscount > 0,
|
|
113
|
+
discount: {
|
|
114
|
+
discount: discounted,
|
|
115
|
+
net: vatNet
|
|
116
|
+
},
|
|
117
|
+
netOfVat: format2(vatSales + vatExemptSales),
|
|
118
|
+
vat,
|
|
119
|
+
serviceCharge,
|
|
120
|
+
togoCharge,
|
|
121
|
+
totalAmount,
|
|
122
|
+
bir: {
|
|
123
|
+
vatSales,
|
|
124
|
+
vatExemptSales,
|
|
125
|
+
vatZeroRatedSales: 0,
|
|
126
|
+
nonTaxableSales: 0,
|
|
127
|
+
vat,
|
|
128
|
+
totalSales: subtotal,
|
|
129
|
+
discount: discounted,
|
|
130
|
+
serviceCharge,
|
|
131
|
+
togoCharge,
|
|
132
|
+
amountPayable: totalAmount
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
32
137
|
function calculateTotals(input) {
|
|
138
|
+
const splitTotals = calculateSplitTotals(input);
|
|
139
|
+
if (splitTotals) return splitTotals;
|
|
33
140
|
const vatRate = Number(input.vatRate || 0) / 100;
|
|
34
141
|
const scRate = Number(input.serviceChargeRate || 0) / 100;
|
|
35
142
|
const discountRate = Number(input.discountRate || 0) / 100;
|
|
@@ -78,6 +185,7 @@ function calculateTotals(input) {
|
|
|
78
185
|
vatNet,
|
|
79
186
|
vat,
|
|
80
187
|
discounted,
|
|
188
|
+
discountBreakdown: getDiscountBreakdown(input.discountType, discounted),
|
|
81
189
|
voucherDiscounted,
|
|
82
190
|
serviceCharge,
|
|
83
191
|
togoCharge,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qrwise/pos-calculations",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Shared POS calculations for QR Wise POS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean --tsconfig tsconfig.json",
|
|
22
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
22
23
|
"prepublishOnly": "npm run build",
|
|
23
24
|
"release:patch": "npm version patch && npm publish",
|
|
24
25
|
"release:minor": "npm version minor && npm publish",
|