@digitalwalletcorp/utils 0.14.0 → 0.16.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.
@@ -200,4 +200,18 @@ export declare class ZonedDateTime {
200
200
  * @returns {string}
201
201
  */
202
202
  toString(): string;
203
+ /**
204
+ * epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
205
+ *
206
+ * @returns {number}
207
+ */
208
+ valueOf(): number;
209
+ /**
210
+ * プリミティブ値への変換
211
+ * 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
212
+ *
213
+ * @param {string} hint
214
+ * @returns {number | string}
215
+ */
216
+ [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string;
203
217
  }
@@ -1,5 +1,5 @@
1
1
  import { DateTime as a } from "luxon";
2
- const d = "UTC", h = "en-US", m = (s) => {
2
+ const h = "UTC", d = "en-US", m = (s) => {
3
3
  if (!s.isValid && s.invalidReason === "unsupported zone")
4
4
  throw new RangeError(s.invalidExplanation ?? s.invalidReason);
5
5
  }, o = (s, t, e, n) => {
@@ -21,7 +21,7 @@ class i {
21
21
  * @param {string} [timezone] IANA名。既定は 'UTC'
22
22
  * @returns {ZonedDateTime}
23
23
  */
24
- static now(t = d) {
24
+ static now(t = h) {
25
25
  const e = a.now().setZone(t);
26
26
  return m(e), new i(e);
27
27
  }
@@ -39,7 +39,7 @@ class i {
39
39
  static parse(t, e) {
40
40
  if (t == null || t === "")
41
41
  return null;
42
- const n = e?.inputTimezone ?? d;
42
+ const n = e?.inputTimezone ?? h;
43
43
  let r = null;
44
44
  if (t instanceof i)
45
45
  r = e?.inputTimezone ? t.dateTime.setZone(e.inputTimezone) : t.dateTime;
@@ -48,11 +48,11 @@ class i {
48
48
  else if (typeof t == "number")
49
49
  r = Number.isFinite(t) ? a.fromMillis(t, { zone: n }) : null;
50
50
  else {
51
- const c = e?.locale ?? h, l = e?.inputFormat ? [e.inputFormat].flat() : [];
52
- for (const f of l) {
51
+ const l = e?.locale ?? d, c = e?.inputFormat ? [e.inputFormat].flat() : [];
52
+ for (const f of c) {
53
53
  const u = a.fromFormat(t, f, {
54
54
  zone: n,
55
- locale: c
55
+ locale: l
56
56
  });
57
57
  if (m(u), u.isValid) {
58
58
  r = u;
@@ -248,7 +248,7 @@ class i {
248
248
  * @returns {string}
249
249
  */
250
250
  format(t, e) {
251
- return this.dateTime.toFormat(t, { locale: e?.locale ?? h });
251
+ return this.dateTime.toFormat(t, { locale: e?.locale ?? d });
252
252
  }
253
253
  /**
254
254
  * 自身のタイムゾーンで、ISO形式の文字列にする
@@ -282,6 +282,24 @@ class i {
282
282
  toString() {
283
283
  return this.toISO();
284
284
  }
285
+ /**
286
+ * epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
287
+ *
288
+ * @returns {number}
289
+ */
290
+ valueOf() {
291
+ return this.toMillis();
292
+ }
293
+ /**
294
+ * プリミティブ値への変換
295
+ * 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
296
+ *
297
+ * @param {string} hint
298
+ * @returns {number | string}
299
+ */
300
+ [Symbol.toPrimitive](t) {
301
+ return t === "number" ? this.toMillis() : this.toISO();
302
+ }
285
303
  }
286
304
  export {
287
305
  i as ZonedDateTime
@@ -1 +1 @@
1
- {"version":3,"file":"zoned-date-time.js","sources":["../src/zoned-date-time.ts"],"sourcesContent":["/**\n * このクラス ZonedDateTime の役割は、日時演算の実体としての luxon を内部に閉じ込め、利用者側に露出させないことにある\n */\nimport { DateTime } from 'luxon';\nimport type { DateInput, DateUnit, Duration, ParseDateOptions, TimeUnit } from './date-util';\n\n/** set で変更する日時の要素。month は1〜12 */\nexport interface ZonedDateTimeFields {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * 日時を文字列にするときのオプション\n */\nexport interface ZonedDateTimeFormatOptions {\n /** 月名・曜日名に使うロケール。既定は 'en-US' */\n locale?: string;\n}\n\nconst DEFAULT_TIMEZONE = 'UTC';\n\nconst DEFAULT_LOCALE = 'en-US';\n\n/**\n * タイムゾーンの指定が不正な場合は、日時の不正とは区別して例外にする\n */\nconst assertZone = (d: DateTime): void => {\n if (!d.isValid && d.invalidReason === 'unsupported zone') {\n throw new RangeError(d.invalidExplanation ?? d.invalidReason);\n }\n};\n\n/**\n * set に渡された要素が min〜max の整数であることを確かめる\n */\nconst assertField = (name: keyof ZonedDateTimeFields, value: number | undefined, min: number, max: number): void => {\n if (value === undefined) {\n return;\n }\n if (!Number.isInteger(value) || value < min || max < value) {\n throw new RangeError(`${name} must be an integer from ${min} to ${max}: ${value}`);\n }\n};\n\n/**\n * 日時を表す不変オブジェクト\n * 演算メソッドは自身を変更せず、結果を新しいインスタンスで返す\n * インスタンスごとにタイムゾーンを持ち、startOf / endOf / set や各要素の参照はそのタイムゾーンで計算する\n */\nexport class ZonedDateTime {\n /**\n * 日時演算インスタンス\n */\n private dateTime: DateTime;\n\n private constructor(dateTime: DateTime) {\n this.dateTime = dateTime;\n }\n\n /**\n * 現在時刻を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} [timezone] IANA名。既定は 'UTC'\n * @returns {ZonedDateTime}\n */\n public static now(timezone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n const d = DateTime.now().setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 値を日時として解釈する\n * 生成したインスタンスは inputTimezone のタイムゾーンを持つ\n * ZonedDateTime を渡した場合、inputTimezone を省略すると渡した ZonedDateTime のタイムゾーンを引き継ぐ\n * duration / startOf / endOf はそのタイムゾーンで計算する\n * 解釈できない値、null / undefined / 空文字は null を返す。タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {DateInput} value\n * @param {ParseDateOptions} [options]\n * @returns {ZonedDateTime | null}\n */\n public static parse(value: DateInput, options?: ParseDateOptions): ZonedDateTime | null {\n if (value == null || value === '') {\n return null;\n }\n const zone = options?.inputTimezone ?? DEFAULT_TIMEZONE;\n let d: DateTime | null = null;\n if (value instanceof ZonedDateTime) {\n d = options?.inputTimezone ? value.dateTime.setZone(options.inputTimezone) : value.dateTime;\n } else if (value instanceof Date) {\n d = DateTime.fromJSDate(value, { zone: zone });\n } else if (typeof value === 'number') {\n d = Number.isFinite(value) ? DateTime.fromMillis(value, { zone: zone }) : null;\n } else {\n const locale = options?.locale ?? DEFAULT_LOCALE;\n const formats = options?.inputFormat ? [options.inputFormat].flat() : [];\n for (const format of formats) {\n const parsed = DateTime.fromFormat(value, format, {\n zone: zone,\n locale: locale\n });\n assertZone(parsed);\n if (parsed.isValid) {\n d = parsed;\n break;\n }\n }\n if (d == null) {\n d = DateTime.fromISO(value, { zone: zone });\n }\n }\n if (d == null) {\n return null;\n }\n assertZone(d);\n if (!d.isValid) {\n return null;\n }\n if (options?.duration) {\n d = d.plus(options.duration);\n }\n if (options?.startOf) {\n d = d.startOf(options.startOf);\n }\n if (options?.endOf) {\n d = d.endOf(options.endOf);\n }\n return new ZonedDateTime(d);\n }\n\n /** 年 */\n public get year(): number {\n return this.dateTime.year;\n }\n\n /** 月(1〜12) */\n public get month(): number {\n return this.dateTime.month;\n }\n\n /** 日 */\n public get day(): number {\n return this.dateTime.day;\n }\n\n /** 時 */\n public get hour(): number {\n return this.dateTime.hour;\n }\n\n /** 分 */\n public get minute(): number {\n return this.dateTime.minute;\n }\n\n /** 秒 */\n public get second(): number {\n return this.dateTime.second;\n }\n\n /** ミリ秒 */\n public get millisecond(): number {\n return this.dateTime.millisecond;\n }\n\n /** 曜日。月曜が1、日曜が7 */\n public get weekday(): number {\n return this.dateTime.weekday;\n }\n\n /** その月の日数 */\n public get daysInMonth(): number {\n return this.dateTime.daysInMonth as number;\n }\n\n /** 夏時間の期間中か */\n public get isInDST(): boolean {\n return this.dateTime.isInDST;\n }\n\n /** タイムゾーン(IANA名) */\n public get timezone(): string {\n return this.dateTime.zoneName as string;\n }\n\n /**\n * 期間を加算した結果を返す\n * 負の値を指定すると減算になる\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public plus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.plus(duration));\n }\n\n /**\n * 期間を減算した結果を返す\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public minus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.minus(duration));\n }\n\n /**\n * 指定した単位の最初の時点に切り捨てた結果を返す(month なら月初の00:00:00.000)\n * week は月曜始まりで切り捨てる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public startOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.startOf(unit));\n }\n\n /**\n * 指定した単位の最後の時点に切り上げた結果を返す(month なら月末の23:59:59.999)\n * week は日曜終わりで切り上げる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public endOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.endOf(unit));\n }\n\n /**\n * 指定した要素を変更した結果を返す\n * 範囲外の値や整数でない値を指定した場合は RangeError をスローする\n * day を指定せずに year / month を変更し、日がその月に無い場合は月末日にする(1月31日に { month: 2 } なら2月末日)\n *\n * @param {ZonedDateTimeFields} fields\n * @returns {ZonedDateTime}\n */\n public set(fields: ZonedDateTimeFields): ZonedDateTime {\n assertField('month', fields.month, 1, 12);\n assertField('hour', fields.hour, 0, 23);\n assertField('minute', fields.minute, 0, 59);\n assertField('second', fields.second, 0, 59);\n assertField('millisecond', fields.millisecond, 0, 999);\n // day の上限は変更後の年月で決まる\n const daysInMonth = this.dateTime.set({\n year: fields.year ?? this.year,\n month: fields.month ?? this.month,\n day: 1\n }).daysInMonth as number;\n assertField('day', fields.day, 1, daysInMonth);\n return new ZonedDateTime(this.dateTime.set(fields));\n }\n\n /**\n * 同じ時刻を別のタイムゾーンで表した結果を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} timezone IANA名\n * @returns {ZonedDateTime}\n */\n public setZone(timezone: string): ZonedDateTime {\n const d = this.dateTime.setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 自身 − other を unit の単位で返す\n * 両方を自身のタイムゾーンで unit の始まりに切り捨ててから差を取るため、暦の上での差になる(23:00 と翌 01:00 の days は 1)\n *\n * @param {ZonedDateTime} other\n * @param {TimeUnit} unit\n * @returns {number}\n */\n public diff(other: ZonedDateTime, unit: TimeUnit): number {\n // 'days' → 'day' のように切り捨ての単位にする\n const dateUnit = unit.slice(0, -1) as DateUnit;\n const target = other.dateTime.setZone(this.dateTime.zone);\n return this.dateTime.startOf(dateUnit).diff(target.startOf(dateUnit), unit).get(unit);\n }\n\n /**\n * 時刻を比較する。タイムゾーンが異なっていても同じ時刻なら等しい\n *\n * @param {ZonedDateTime} other\n * @returns {-1 | 0 | 1} 自身が前なら-1、等しければ0、後なら1\n */\n public compareTo(other: ZonedDateTime): -1 | 0 | 1 {\n return Math.sign(this.toMillis() - other.toMillis()) as -1 | 0 | 1;\n }\n\n /**\n * 同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public eq(other: ZonedDateTime): boolean {\n return this.compareTo(other) === 0;\n }\n\n /**\n * 自身が前の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lt(other: ZonedDateTime): boolean {\n return this.compareTo(other) < 0;\n }\n\n /**\n * 自身が前か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lte(other: ZonedDateTime): boolean {\n return this.compareTo(other) <= 0;\n }\n\n /**\n * 自身が後の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gt(other: ZonedDateTime): boolean {\n return 0 < this.compareTo(other);\n }\n\n /**\n * 自身が後か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gte(other: ZonedDateTime): boolean {\n return 0 <= this.compareTo(other);\n }\n\n /**\n * 自身のタイムゾーンで、指定した書式の文字列にする\n *\n * @param {string} outputFormat\n * @param {ZonedDateTimeFormatOptions} [options]\n * @returns {string}\n */\n public format(outputFormat: string, options?: ZonedDateTimeFormatOptions): string {\n return this.dateTime.toFormat(outputFormat, { locale: options?.locale ?? DEFAULT_LOCALE });\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toISO(): string {\n return this.dateTime.toISO() as string;\n }\n\n /**\n * Date に変換する\n *\n * @returns {Date}\n */\n public toDate(): Date {\n return this.dateTime.toJSDate();\n }\n\n /**\n * epoch ミリ秒に変換する\n *\n * @returns {number}\n */\n public toMillis(): number {\n return this.dateTime.toMillis();\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toString(): string {\n return this.toISO();\n }\n}\n"],"names":["DEFAULT_TIMEZONE","DEFAULT_LOCALE","assertZone","d","assertField","name","value","min","max","ZonedDateTime","dateTime","timezone","DateTime","options","zone","locale","formats","format","parsed","duration","unit","fields","daysInMonth","other","dateUnit","target","outputFormat"],"mappings":"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"}
1
+ {"version":3,"file":"zoned-date-time.js","sources":["../src/zoned-date-time.ts"],"sourcesContent":["/**\n * このクラス ZonedDateTime の役割は、日時演算の実体としての luxon を内部に閉じ込め、利用者側に露出させないことにある\n */\nimport { DateTime } from 'luxon';\nimport type { DateInput, DateUnit, Duration, ParseDateOptions, TimeUnit } from './date-util';\n\n/** set で変更する日時の要素。month は1〜12 */\nexport interface ZonedDateTimeFields {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * 日時を文字列にするときのオプション\n */\nexport interface ZonedDateTimeFormatOptions {\n /** 月名・曜日名に使うロケール。既定は 'en-US' */\n locale?: string;\n}\n\nconst DEFAULT_TIMEZONE = 'UTC';\n\nconst DEFAULT_LOCALE = 'en-US';\n\n/**\n * タイムゾーンの指定が不正な場合は、日時の不正とは区別して例外にする\n */\nconst assertZone = (d: DateTime): void => {\n if (!d.isValid && d.invalidReason === 'unsupported zone') {\n throw new RangeError(d.invalidExplanation ?? d.invalidReason);\n }\n};\n\n/**\n * set に渡された要素が min〜max の整数であることを確かめる\n */\nconst assertField = (name: keyof ZonedDateTimeFields, value: number | undefined, min: number, max: number): void => {\n if (value === undefined) {\n return;\n }\n if (!Number.isInteger(value) || value < min || max < value) {\n throw new RangeError(`${name} must be an integer from ${min} to ${max}: ${value}`);\n }\n};\n\n/**\n * 日時を表す不変オブジェクト\n * 演算メソッドは自身を変更せず、結果を新しいインスタンスで返す\n * インスタンスごとにタイムゾーンを持ち、startOf / endOf / set や各要素の参照はそのタイムゾーンで計算する\n */\nexport class ZonedDateTime {\n /**\n * 日時演算インスタンス\n */\n private dateTime: DateTime;\n\n private constructor(dateTime: DateTime) {\n this.dateTime = dateTime;\n }\n\n /**\n * 現在時刻を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} [timezone] IANA名。既定は 'UTC'\n * @returns {ZonedDateTime}\n */\n public static now(timezone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n const d = DateTime.now().setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 値を日時として解釈する\n * 生成したインスタンスは inputTimezone のタイムゾーンを持つ\n * ZonedDateTime を渡した場合、inputTimezone を省略すると渡した ZonedDateTime のタイムゾーンを引き継ぐ\n * duration / startOf / endOf はそのタイムゾーンで計算する\n * 解釈できない値、null / undefined / 空文字は null を返す。タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {DateInput} value\n * @param {ParseDateOptions} [options]\n * @returns {ZonedDateTime | null}\n */\n public static parse(value: DateInput, options?: ParseDateOptions): ZonedDateTime | null {\n if (value == null || value === '') {\n return null;\n }\n const zone = options?.inputTimezone ?? DEFAULT_TIMEZONE;\n let d: DateTime | null = null;\n if (value instanceof ZonedDateTime) {\n d = options?.inputTimezone ? value.dateTime.setZone(options.inputTimezone) : value.dateTime;\n } else if (value instanceof Date) {\n d = DateTime.fromJSDate(value, { zone: zone });\n } else if (typeof value === 'number') {\n d = Number.isFinite(value) ? DateTime.fromMillis(value, { zone: zone }) : null;\n } else {\n const locale = options?.locale ?? DEFAULT_LOCALE;\n const formats = options?.inputFormat ? [options.inputFormat].flat() : [];\n for (const format of formats) {\n const parsed = DateTime.fromFormat(value, format, {\n zone: zone,\n locale: locale\n });\n assertZone(parsed);\n if (parsed.isValid) {\n d = parsed;\n break;\n }\n }\n if (d == null) {\n d = DateTime.fromISO(value, { zone: zone });\n }\n }\n if (d == null) {\n return null;\n }\n assertZone(d);\n if (!d.isValid) {\n return null;\n }\n if (options?.duration) {\n d = d.plus(options.duration);\n }\n if (options?.startOf) {\n d = d.startOf(options.startOf);\n }\n if (options?.endOf) {\n d = d.endOf(options.endOf);\n }\n return new ZonedDateTime(d);\n }\n\n /** 年 */\n public get year(): number {\n return this.dateTime.year;\n }\n\n /** 月(1〜12) */\n public get month(): number {\n return this.dateTime.month;\n }\n\n /** 日 */\n public get day(): number {\n return this.dateTime.day;\n }\n\n /** 時 */\n public get hour(): number {\n return this.dateTime.hour;\n }\n\n /** 分 */\n public get minute(): number {\n return this.dateTime.minute;\n }\n\n /** 秒 */\n public get second(): number {\n return this.dateTime.second;\n }\n\n /** ミリ秒 */\n public get millisecond(): number {\n return this.dateTime.millisecond;\n }\n\n /** 曜日。月曜が1、日曜が7 */\n public get weekday(): number {\n return this.dateTime.weekday;\n }\n\n /** その月の日数 */\n public get daysInMonth(): number {\n return this.dateTime.daysInMonth as number;\n }\n\n /** 夏時間の期間中か */\n public get isInDST(): boolean {\n return this.dateTime.isInDST;\n }\n\n /** タイムゾーン(IANA名) */\n public get timezone(): string {\n return this.dateTime.zoneName as string;\n }\n\n /**\n * 期間を加算した結果を返す\n * 負の値を指定すると減算になる\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public plus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.plus(duration));\n }\n\n /**\n * 期間を減算した結果を返す\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public minus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.minus(duration));\n }\n\n /**\n * 指定した単位の最初の時点に切り捨てた結果を返す(month なら月初の00:00:00.000)\n * week は月曜始まりで切り捨てる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public startOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.startOf(unit));\n }\n\n /**\n * 指定した単位の最後の時点に切り上げた結果を返す(month なら月末の23:59:59.999)\n * week は日曜終わりで切り上げる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public endOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.endOf(unit));\n }\n\n /**\n * 指定した要素を変更した結果を返す\n * 範囲外の値や整数でない値を指定した場合は RangeError をスローする\n * day を指定せずに year / month を変更し、日がその月に無い場合は月末日にする(1月31日に { month: 2 } なら2月末日)\n *\n * @param {ZonedDateTimeFields} fields\n * @returns {ZonedDateTime}\n */\n public set(fields: ZonedDateTimeFields): ZonedDateTime {\n assertField('month', fields.month, 1, 12);\n assertField('hour', fields.hour, 0, 23);\n assertField('minute', fields.minute, 0, 59);\n assertField('second', fields.second, 0, 59);\n assertField('millisecond', fields.millisecond, 0, 999);\n // day の上限は変更後の年月で決まる\n const daysInMonth = this.dateTime.set({\n year: fields.year ?? this.year,\n month: fields.month ?? this.month,\n day: 1\n }).daysInMonth as number;\n assertField('day', fields.day, 1, daysInMonth);\n return new ZonedDateTime(this.dateTime.set(fields));\n }\n\n /**\n * 同じ時刻を別のタイムゾーンで表した結果を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} timezone IANA名\n * @returns {ZonedDateTime}\n */\n public setZone(timezone: string): ZonedDateTime {\n const d = this.dateTime.setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 自身 − other を unit の単位で返す\n * 両方を自身のタイムゾーンで unit の始まりに切り捨ててから差を取るため、暦の上での差になる(23:00 と翌 01:00 の days は 1)\n *\n * @param {ZonedDateTime} other\n * @param {TimeUnit} unit\n * @returns {number}\n */\n public diff(other: ZonedDateTime, unit: TimeUnit): number {\n // 'days' → 'day' のように切り捨ての単位にする\n const dateUnit = unit.slice(0, -1) as DateUnit;\n const target = other.dateTime.setZone(this.dateTime.zone);\n return this.dateTime.startOf(dateUnit).diff(target.startOf(dateUnit), unit).get(unit);\n }\n\n /**\n * 時刻を比較する。タイムゾーンが異なっていても同じ時刻なら等しい\n *\n * @param {ZonedDateTime} other\n * @returns {-1 | 0 | 1} 自身が前なら-1、等しければ0、後なら1\n */\n public compareTo(other: ZonedDateTime): -1 | 0 | 1 {\n return Math.sign(this.toMillis() - other.toMillis()) as -1 | 0 | 1;\n }\n\n /**\n * 同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public eq(other: ZonedDateTime): boolean {\n return this.compareTo(other) === 0;\n }\n\n /**\n * 自身が前の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lt(other: ZonedDateTime): boolean {\n return this.compareTo(other) < 0;\n }\n\n /**\n * 自身が前か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lte(other: ZonedDateTime): boolean {\n return this.compareTo(other) <= 0;\n }\n\n /**\n * 自身が後の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gt(other: ZonedDateTime): boolean {\n return 0 < this.compareTo(other);\n }\n\n /**\n * 自身が後か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gte(other: ZonedDateTime): boolean {\n return 0 <= this.compareTo(other);\n }\n\n /**\n * 自身のタイムゾーンで、指定した書式の文字列にする\n *\n * @param {string} outputFormat\n * @param {ZonedDateTimeFormatOptions} [options]\n * @returns {string}\n */\n public format(outputFormat: string, options?: ZonedDateTimeFormatOptions): string {\n return this.dateTime.toFormat(outputFormat, { locale: options?.locale ?? DEFAULT_LOCALE });\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toISO(): string {\n return this.dateTime.toISO() as string;\n }\n\n /**\n * Date に変換する\n *\n * @returns {Date}\n */\n public toDate(): Date {\n return this.dateTime.toJSDate();\n }\n\n /**\n * epoch ミリ秒に変換する\n *\n * @returns {number}\n */\n public toMillis(): number {\n return this.dateTime.toMillis();\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toString(): string {\n return this.toISO();\n }\n\n /**\n * epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため\n *\n * @returns {number}\n */\n public valueOf(): number {\n return this.toMillis();\n }\n\n /**\n * プリミティブ値への変換\n * 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする\n *\n * @param {string} hint\n * @returns {number | string}\n */\n public [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string {\n return hint === 'number' ? this.toMillis() : this.toISO();\n }\n}\n"],"names":["DEFAULT_TIMEZONE","DEFAULT_LOCALE","assertZone","d","assertField","name","value","min","max","ZonedDateTime","dateTime","timezone","DateTime","options","zone","locale","formats","format","parsed","duration","unit","fields","daysInMonth","other","dateUnit","target","outputFormat","hint"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalwalletcorp/utils",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "A javascript utility.",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
package/src/decimal.ts CHANGED
@@ -8,7 +8,7 @@ import { Big } from 'big.js';
8
8
  /**
9
9
  * 数値として扱える値の型
10
10
  */
11
- export type NumberSource = number | string | bigint;
11
+ export type NumberSource = number | string | bigint | Decimal;
12
12
 
13
13
  /**
14
14
  * 丸めモード
@@ -41,7 +41,7 @@ export type RoundingMode = typeof ROUNDING_MODE[keyof typeof ROUNDING_MODE];
41
41
  * Decimalの生成・演算に渡せる値の型
42
42
  * null/undefined/空文字/NaNは0とみなす(divの割る値は1とみなす)
43
43
  */
44
- export type DecimalSource = NumberSource | Decimal | null | undefined;
44
+ export type DecimalSource = NumberSource | null | undefined;
45
45
 
46
46
  /** 除算で保持する小数桁数 */
47
47
  const DIVISION_SCALE = 20;
@@ -21,7 +21,7 @@ const isBlank = (value: unknown): value is string => typeof value === 'string' &
21
21
  * long(64bit)の範囲(-9223372036854775808〜9223372036854775807)の値か判定する
22
22
  * Javascriptのnumberの範囲は(-9007199254740991〜9007199254740991)である
23
23
  *
24
- * @param {string | bigint} value
24
+ * @param {string | bigint | Decimal} value
25
25
  * @param {*} [options]
26
26
  * ├ minValue number 最小値を指定する場合(0を指定すると負数の場合falseを返す)
27
27
  * 不正な値を指定した場合は無視される(最小値を-9223372036854775808とみなす)
@@ -29,7 +29,7 @@ const isBlank = (value: unknown): value is string => typeof value === 'string' &
29
29
  * @see Number.MAX_SAFE_INTEGER
30
30
  * @see Number.MIN_SAFE_INTEGER
31
31
  */
32
- export function isLongValue(value: string | bigint, options?: {
32
+ export function isLongValue(value: string | bigint | Decimal, options?: {
33
33
  minValue?: number;
34
34
  }): boolean {
35
35
  if (value == null || isBlank(value)) {
@@ -83,7 +83,7 @@ export function formatComma(value: NumberSource | null | undefined, scale?: numb
83
83
  }
84
84
  break;
85
85
  default:
86
- // bigintの場合
86
+ // bigint・Decimalの場合
87
87
  strValue = value.toString();
88
88
  }
89
89
  const matches = NUMBER_PATTERN.exec(strValue) as RegExpExecArray;
@@ -469,8 +469,12 @@ export function toNumber<O extends ToNumberOptions = Record<never, never>>(value
469
469
  case 'bigint':
470
470
  result = Number(value);
471
471
  break;
472
- default:
472
+ case 'string':
473
473
  result = Number(removeComma(value).trim());
474
+ break;
475
+ default:
476
+ // Decimalの場合
477
+ result = value.toNumber();
474
478
  }
475
479
  if (Number.isNaN(result)) {
476
480
  switch (options?.nan) {
@@ -524,7 +528,7 @@ export function formatBytes(
524
528
  }
525
529
  break;
526
530
  default:
527
- // bigintの場合
531
+ // bigint・Decimalの場合
528
532
  decimalValue = new Decimal(bytes);
529
533
  }
530
534
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
@@ -392,4 +392,24 @@ export class ZonedDateTime {
392
392
  public toString(): string {
393
393
  return this.toISO();
394
394
  }
395
+
396
+ /**
397
+ * epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
398
+ *
399
+ * @returns {number}
400
+ */
401
+ public valueOf(): number {
402
+ return this.toMillis();
403
+ }
404
+
405
+ /**
406
+ * プリミティブ値への変換
407
+ * 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
408
+ *
409
+ * @param {string} hint
410
+ * @returns {number | string}
411
+ */
412
+ public [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string {
413
+ return hint === 'number' ? this.toMillis() : this.toISO();
414
+ }
395
415
  }
@@ -1,2 +0,0 @@
1
- "use strict";const i=require("./decimal.cjs"),k=new i.Decimal("-9223372036854775808"),C=new i.Decimal("9223372036854775807"),D=new RegExp("([+-]?)([0-9]*)[.]?([0-9]*)"),V=/^[+-]?(\d+\.?\d*|\.\d+)(e[+-]?\d+)?$/i,d=e=>typeof e=="string"&&e.trim()==="";function w(e,t){if(e==null||d(e))return!1;const r=Number.isFinite(t?.minValue)?new i.Decimal(t.minValue):k;try{return r.lte(e)&&C.gte(e)}catch{return!1}}function g(e,t,r){if(e==null||e==="")return"";let n;switch(typeof e){case"number":if(!Number.isFinite(e))return String(e);n=new i.Decimal(e).toString();break;case"string":if(n=a(e).trim(),!V.test(n))return e;/e/i.test(n)&&(n=`${n.startsWith("+")?"+":""}${new i.Decimal(n).toString()}`);break;default:n=e.toString()}const o=D.exec(n),l=o[1];let u=o[2]||"0",c=o[3],f,s=new i.Decimal(`${l==="-"?"-":""}${u}.${c}`);if(t!=null){s=s.round(t,r??i.ROUNDING_MODE.roundHalfUp);const N=D.exec(s.toString());u=N[2],c=N[3],f=t}else f=c.length;const b=s.eq(0)?"":l;return u=u.replace(/(\d)(?=(\d{3})+$)/g,"$1,"),c=`${c}${"0".repeat(f)}`.substring(0,f),c===""?`${b}${u}`:`${b}${u}.${c}`}function a(e){return e.replace(/,/g,"")}function $(e,t){return new Intl.NumberFormat(t,{notation:"compact"}).format(e)}function p(e,t,r){let n=new i.Decimal(e);for(const o of t)n=n[o.operator](o.value);return r?.scale!=null&&(n=n.round(r.scale,r.roundingMode??i.ROUNDING_MODE.roundHalfUp)),n.toNumber()}function S(e,...t){let r=new i.Decimal(e);for(const n of t)r=r.add(n);return r.toNumber()}function M(e,...t){let r=new i.Decimal(e);for(const n of t)r=r.sub(n);return r.toNumber()}function O(e,...t){let r=new i.Decimal(e);for(const n of t)r=r.times(n);return r.toNumber()}function h(e,...t){let r=new i.Decimal(e);for(const n of t)r=r.div(n);return r.toNumber()}function m(e,t){return new i.Decimal(e).compareTo(t)}function U(e,t){return m(e,t)===0}function _(e,t){return m(e,t)<0}function R(e,t){return m(e,t)<=0}function E(e,t){return 0<m(e,t)}function G(e,t){return 0<=m(e,t)}function I(e,t,r){if(e==null)return null;const n=r??i.ROUNDING_MODE.roundHalfUp;switch(typeof e){case"number":return Number.isFinite(e)?new i.Decimal(e).round(t,n).toNumber():e;case"string":{if(d(e))return null;try{return new i.Decimal(e).round(t,n).toNumber()}catch{return Number.NaN}}default:return new i.Decimal(e).round(t,n).toNumber()}}function T(e,t){if(e==null)return"";if(d(e)||typeof e=="number"&&!Number.isFinite(e))return String(e);try{const r=new i.Decimal(e);return t?.scale!=null?r.toFixed(t.scale,t.roundingMode??i.ROUNDING_MODE.roundHalfUp):r.toString()}catch{return String(e)}}function B(e,t){if(e==null||d(e))switch(t?.empty){case"undefined":return;case"zero":return 0;default:return null}let r;switch(typeof e){case"number":r=e;break;case"bigint":r=Number(e);break;default:r=Number(a(e).trim())}if(Number.isNaN(r))switch(t?.nan){case"null":return null;case"undefined":return;default:return r}return r}function y(e,t){if(e==null||e==="")return[String(e),""];let r;switch(typeof e){case"number":if(Number.isNaN(e))return["NaN",""];r=new i.Decimal(e);break;case"string":try{r=new i.Decimal(a(e))}catch{return[e,""]}break;default:r=new i.Decimal(e)}const n=["B","KB","MB","GB","TB"];let o=0;for(;r.gte(1024)&&o<n.length-1;)r=r.div(1024),o++;const l=t?.scale??2,u=t?.roundingMode??i.ROUNDING_MODE.roundHalfUp;return t?.format?[g(r.toString(),l,u),n[o]]:[r.round(l,u).toString(),n[o]]}const F=Object.freeze(Object.defineProperty({__proto__:null,ROUNDING_MODE:i.ROUNDING_MODE,add:S,calc:p,compareTo:m,div:h,eq:U,formatBytes:y,formatComma:g,formatCompact:$,gt:E,gte:G,isLongValue:w,lt:_,lte:R,removeComma:a,round:I,sub:M,times:O,toNumber:B,toString:T},Symbol.toStringTag,{value:"Module"}));exports.add=S;exports.calc=p;exports.compareTo=m;exports.div=h;exports.eq=U;exports.formatBytes=y;exports.formatComma=g;exports.formatCompact=$;exports.gt=E;exports.gte=G;exports.isLongValue=w;exports.lt=_;exports.lte=R;exports.numberUtil=F;exports.removeComma=a;exports.round=I;exports.sub=M;exports.times=O;exports.toNumber=B;exports.toString=T;
2
- //# sourceMappingURL=number-util-BrDEKYJo.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"number-util-BrDEKYJo.cjs","sources":["../src/number-util.ts"],"sourcesContent":["import { Decimal, ROUNDING_MODE } from './decimal';\nimport type { NumberSource, RoundingMode } from './decimal';\n\nexport { ROUNDING_MODE };\nexport type { NumberSource, RoundingMode };\n\n// 64bit整数の範囲\nconst MIN_LONG = new Decimal('-9223372036854775808');\nconst MAX_LONG = new Decimal('9223372036854775807');\n\n/** 数値パターン */\nconst NUMBER_PATTERN = new RegExp('([\\+\\-]?)([0-9]*)[\\.]?([0-9]*)');\n\n/** 数値として解釈できる文字列のパターン(符号・小数点・指数表記) */\nconst NUMERIC_STRING_PATTERN = /^[+-]?(\\d+\\.?\\d*|\\.\\d+)(e[+-]?\\d+)?$/i;\n\n// 空文字・空白のみの文字列はtrueを返す\nconst isBlank = (value: unknown): value is string => typeof value === 'string' && value.trim() === '';\n\n/**\n * long(64bit)の範囲(-9223372036854775808〜9223372036854775807)の値か判定する\n * Javascriptのnumberの範囲は(-9007199254740991〜9007199254740991)である\n *\n * @param {string | bigint} value\n * @param {*} [options]\n * ├ minValue number 最小値を指定する場合(0を指定すると負数の場合falseを返す)\n * 不正な値を指定した場合は無視される(最小値を-9223372036854775808とみなす)\n * @returns {boolean}\n * @see Number.MAX_SAFE_INTEGER\n * @see Number.MIN_SAFE_INTEGER\n */\nexport function isLongValue(value: string | bigint, options?: {\n minValue?: number;\n}): boolean {\n if (value == null || isBlank(value)) {\n return false;\n }\n const min = Number.isFinite(options?.minValue) ? new Decimal(options!.minValue) : MIN_LONG;\n try {\n // -9223372036854775808 <= value <= 9223372036854775807\n return min.lte(value) && MAX_LONG.gte(value);\n } catch (error) {\n // 数値として解釈できない値\n return false;\n }\n}\n\n/**\n * 3桁ごとカンマ区切りした文字列を返す\n * 指数表記の値(1e21など)は通常の表記に展開してから区切る\n * 数値として解釈できない文字列はそのまま返し、NaN/Infinityは \"NaN\"/\"Infinity\"/\"-Infinity\" を返す\n *\n * @param {NumberSource | null | undefined} value 値\n * @param {number} [scale] 小数点桁数(補助桁数)\n * @param {RoundingMode} [roundingMode] 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * @returns {string}\n */\nexport function formatComma(value: NumberSource | null | undefined, scale?: number, roundingMode?: RoundingMode): string {\n if (value == null || value === '') {\n // 空文字を返却\n return '';\n }\n let strValue: string;\n switch (typeof value) {\n case 'number':\n if (!Number.isFinite(value)) {\n // \"NaN\" / \"Infinity\" / \"-Infinity\" を返却\n return String(value);\n }\n // toString()は1e21以上や1e-7以下を指数表記にするため、Decimalで通常の表記に展開する\n strValue = new Decimal(value).toString();\n break;\n case 'string':\n strValue = removeComma(value).trim();\n if (!NUMERIC_STRING_PATTERN.test(strValue)) {\n // 元の文字列を返却\n return value;\n }\n if (/e/i.test(strValue)) {\n // 指数表記を通常の表記に展開する。表示用に '+' を付け直す\n const plusSign = strValue.startsWith('+') ? '+' : '';\n strValue = `${plusSign}${new Decimal(strValue).toString()}`;\n }\n break;\n default:\n // bigintの場合\n strValue = value.toString();\n }\n const matches = NUMBER_PATTERN.exec(strValue) as RegExpExecArray;\n const sign = matches[1];\n let natural = matches[2] || '0';\n let decimal = matches[3];\n let dp: number;\n let decimalValue = new Decimal(`${sign === '-' ? '-' : ''}${natural}.${decimal}`);\n if (scale != null) {\n decimalValue = decimalValue.round(scale, roundingMode ?? ROUNDING_MODE.roundHalfUp);\n const roundedMatches = NUMBER_PATTERN.exec(decimalValue.toString()) as RegExpExecArray;\n natural = roundedMatches[2];\n decimal = roundedMatches[3];\n dp = scale;\n } else {\n dp = decimal.length;\n }\n // 丸めた結果がゼロになる場合('-0.001' を小数2桁にするなど)に \"-0.00\" とならないよう、丸めた後の値で判定する\n const displaySign = decimalValue.eq(0) ? '' : sign;\n natural = natural.replace(/(\\d)(?=(\\d{3})+$)/g, '$1,');\n decimal = `${decimal}${'0'.repeat(dp)}`.substring(0, dp);\n return decimal === ''\n ? `${displaySign}${natural}`\n : `${displaySign}${natural}.${decimal}`;\n}\n\n/**\n * カンマを除去する\n *\n * @param {string} value 入力値\n * @returns {string} カンマを取り除いた文字列\n */\nexport function removeComma(value: string): string {\n return value.replace(/,/g, '');\n}\n\n/**\n * 数値を表示ロケールの短縮表記にする。\n * en は 1.2K/3.4M/5.6B、ja は 12万/34億 のように単位が切り替わる。\n *\n * @param {number} value 値\n * @param {string} locale 表示ロケール(例 'ja' / 'en')\n * @returns {string} 短縮表記の文字列\n */\nexport function formatCompact(value: number, locale: string): string {\n return new Intl.NumberFormat(locale, { notation: 'compact' }).format(value);\n}\n\nexport type Operator = 'add' | 'sub' | 'times' | 'div';\n\nexport interface OperationItem {\n operator: Operator;\n value: NumberSource | null | undefined;\n}\n\n/**\n * 複数の演算をまとめて計算する\n * 計算途中は精度を保持し、最後にnumberへ変換する\n * この関数では四則演算の優先順位はなく、与えられた配列の順で計算を行う\n * * 優先順位やカッコの概念がある場合は事前に計算したうえでこの関数を利用する\n *\n * 例)\n * calc(\n * '123',\n * [\n * { operator: 'add', value: '123' },\n * { operator: 'sub', value: 100 },\n * { operator: 'times', value: 2 },\n * { operator: 'div', value: 3 }\n * ]\n * )\n * 123 + 123 = 246\n * 246 - 100 = 146\n * 146 * 2 = 292\n * 292 / 3 = 97.33333333\n *\n * null等の扱いは add / sub / times / div と同じ\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} initialValue\n * @param {OperationItem[]} operationItems\n * ├ operator: Operator\n * ├ value: NumberSource | null | undefined\n * @param {*} [options]\n * ├ scale 計算結果を丸める小数桁数。指定しない場合は丸めない\n * ├ roundingMode 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * @returns {number}\n */\nexport function calc(initialValue: NumberSource | null | undefined, operationItems: OperationItem[], options?: {\n scale?: number;\n roundingMode?: RoundingMode;\n}): number {\n let decimal = new Decimal(initialValue);\n for (const item of operationItems) {\n decimal = decimal[item.operator](item.value);\n }\n if (options?.scale != null) {\n decimal = decimal.round(options.scale, options.roundingMode ?? ROUNDING_MODE.roundHalfUp);\n }\n return decimal.toNumber();\n}\n\n/**\n * 加算を行う\n * null/undefined/空文字/NaNは0と見做されるため、演算結果に影響しない\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function add(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.add(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 減算を行う\n * null/undefined/空文字/NaNは0と見做されるため、演算結果に影響しない\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function sub(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.sub(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 乗算を行う\n * null/undefined/空文字/NaNは0と見做されるため、演算結果は0になる\n * 元の値を保持したい場合は times(price, discount ?? 1) のようにフォールバック値を指定する\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function times(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.times(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 除算を行う\n * 割る値のnull/undefined/空文字/NaNは1と見做されるため、演算結果に影響しない\n * 割る値に0を指定した場合はゼロ除算エラーになる\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function div(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.div(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 2つの値を数値として比較する\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {-1 | 0 | 1} value1がvalue2より小さい場合は-1、等しい場合は0、大きい場合は1\n */\nexport function compareTo(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): -1 | 0 | 1 {\n return new Decimal(value1).compareTo(value2);\n}\n\n/**\n * 2つの値が数値として等しいかを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function eq(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return compareTo(value1, value2) === 0;\n}\n\n/**\n * value1がvalue2より小さいかを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function lt(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return compareTo(value1, value2) < 0;\n}\n\n/**\n * value1がvalue2以下かを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function lte(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return compareTo(value1, value2) <= 0;\n}\n\n/**\n * value1がvalue2より大きいかを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function gt(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return 0 < compareTo(value1, value2);\n}\n\n/**\n * value1がvalue2以上かを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function gte(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return 0 <= compareTo(value1, value2);\n}\n\n/**\n * 数値を指定した桁で丸める\n * null/undefined/空文字はnull、数値として解釈できない文字列はNaNを返す\n * NaN/Infinityはそのまま返す\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value\n * @param {number} scale\n * @param {RoundingMode} [roundingMode] デフォルトは 1: 四捨五入\n * 0 切り捨て\n * 1 四捨五入\n * 2 ISO丸め\n * 3 切り上げ\n * @returns {number | null}\n * @see ROUNDING_MODE\n */\nexport function round(\n value: NumberSource | null | undefined,\n scale: number,\n roundingMode?: RoundingMode\n): number | null {\n if (value == null) {\n return null;\n }\n const rm = roundingMode ?? ROUNDING_MODE.roundHalfUp;\n switch (typeof value) {\n case 'number':\n if (!Number.isFinite(value)) {\n // NaN/Infinityはそのまま返す\n return value;\n }\n return new Decimal(value).round(scale, rm).toNumber();\n case 'string': {\n if (isBlank(value)) {\n // 空文字は値なしとしてnullと同じ扱いにする\n return null;\n }\n try {\n return new Decimal(value).round(scale, rm).toNumber();\n } catch (error) {\n // 数値として解釈できない文字列\n return Number.NaN;\n }\n }\n default:\n return new Decimal(value).round(scale, rm).toNumber();\n }\n}\n\n/**\n * 数値文字列に変換する\n * 指数表記にはならず、通常の表記で返す\n * 数値として解釈できない値はString(value)を返す\n *\n * @param {NumberSource | null | undefined} value\n * @param {*} [options]\n * ├ scale 小数桁数。指定しない場合は丸めずにすべての桁を返す\n * ├ roundingMode 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * @returns {string}\n * @see ROUNDING_MODE\n */\nexport function toString(\n value: NumberSource | null | undefined,\n options?: {\n scale?: number;\n roundingMode?: RoundingMode;\n }\n): string {\n if (value == null) {\n return '';\n }\n if (isBlank(value) || (typeof value === 'number' && !Number.isFinite(value))) {\n // 空文字・NaN・Infinityは数値として扱わない\n return String(value);\n }\n try {\n const decimal = new Decimal(value);\n return options?.scale != null\n ? decimal.toFixed(options.scale, options.roundingMode ?? ROUNDING_MODE.roundHalfUp)\n : decimal.toString();\n } catch (error) {\n return String(value);\n }\n}\n\n/** toNumber のオプション */\nexport interface ToNumberOptions {\n /** 未指定(null・undefined・空白のみの文字列)のときに返す値。デフォルトは 'null' */\n empty?: 'null' | 'undefined' | 'zero';\n /** 数値として解釈できない(結果が NaN になる)ときに返す値。デフォルトは 'NaN' */\n nan?: 'NaN' | 'null' | 'undefined';\n}\n\n/** options.empty に応じた未指定時の戻り値の型。'zero' は number に含まれるので never */\ntype EmptyResult<O extends ToNumberOptions> = O extends { empty?: infer E }\n ? E extends 'undefined' ? undefined : E extends 'zero' ? never : null\n : null;\n\n/** options.nan に応じた変換不可時の戻り値の型。'NaN' は number に含まれるので never */\ntype NanResult<O extends ToNumberOptions> = O extends { nan?: infer N }\n ? N extends 'null' ? null : N extends 'undefined' ? undefined : never\n : never;\n\n/**\n * 数値に変換する\n * 文字列はカンマと前後の空白を除いてから変換する\n * null・undefined・空白のみの文字列は未指定として扱い、options.empty に応じて null(デフォルト)・undefined・0 のいずれかを返す\n * 数値として解釈できない場合は options.nan に応じて NaN(デフォルト)・null・undefined のいずれかを返す\n *\n * @param {NumberSource | null | undefined} value\n * @param {ToNumberOptions} [options]\n * ├ empty 未指定のときに返す値。'null'(デフォルト) | 'undefined' | 'zero'\n * └ nan 数値として解釈できないときに返す値。'NaN'(デフォルト) | 'null' | 'undefined'\n * @returns {number | EmptyResult<O> | NanResult<O>} 戻り値の型は options に連動する\n */\nexport function toNumber<O extends ToNumberOptions = Record<never, never>>(value: NumberSource | null | undefined, options?: O): number | EmptyResult<O> | NanResult<O> {\n type Result = number | EmptyResult<O> | NanResult<O>;\n if (value == null || isBlank(value)) {\n switch (options?.empty) {\n case 'undefined':\n return undefined as Result;\n case 'zero':\n return 0;\n default:\n return null as Result;\n }\n }\n let result: number;\n switch (typeof value) {\n case 'number':\n result = value;\n break;\n case 'bigint':\n result = Number(value);\n break;\n default:\n result = Number(removeComma(value).trim());\n }\n if (Number.isNaN(result)) {\n switch (options?.nan) {\n case 'null':\n return null as Result;\n case 'undefined':\n return undefined as Result;\n default:\n return result;\n }\n }\n return result;\n}\n\n/**\n * 渡されたバイト数値を桁数に応じてMB,GBなどに単位を変更する\n *\n * @param {NumberSource} bytes\n * @param {*} [options]\n * ┝ scale 小数以下桁数 デフォルト:2\n * ┝ roundingMode 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * ┝ format フォーマットするか。trueを指定した場合、3桁カンマ区切り+小数末尾0の桁揃え\n * @returns {[string, string]} 精度以下を丸めた数値(文字列)と単位をタプルで返す\n */\nexport function formatBytes(\n bytes: NumberSource,\n options?: {\n scale?: number;\n roundingMode?: RoundingMode;\n format?: boolean;\n }\n): [string, string] {\n if (bytes == null || bytes === '') {\n return [String(bytes), ''];\n }\n let decimalValue: Decimal;\n switch (typeof bytes) {\n case 'number':\n if (Number.isNaN(bytes)) {\n // \"NaN\" を返却\n return ['NaN', ''];\n }\n decimalValue = new Decimal(bytes);\n break;\n case 'string':\n try {\n decimalValue = new Decimal(removeComma(bytes));\n } catch (error) {\n // 元の文字列を返却\n return [bytes, ''];\n }\n break;\n default:\n // bigintの場合\n decimalValue = new Decimal(bytes);\n }\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n let i = 0;\n while (decimalValue.gte(1024) && i < units.length - 1) {\n decimalValue = decimalValue.div(1024);\n i++;\n }\n const scale = options?.scale ?? 2;\n const roundingMode = options?.roundingMode ?? ROUNDING_MODE.roundHalfUp;\n if (options?.format) {\n return [formatComma(decimalValue.toString(), scale, roundingMode), units[i]];\n }\n return [decimalValue.round(scale, roundingMode).toString(), units[i]];\n}\n"],"names":["MIN_LONG","Decimal","MAX_LONG","NUMBER_PATTERN","NUMERIC_STRING_PATTERN","isBlank","value","isLongValue","options","min","formatComma","scale","roundingMode","strValue","removeComma","matches","sign","natural","decimal","dp","decimalValue","ROUNDING_MODE","roundedMatches","displaySign","formatCompact","locale","calc","initialValue","operationItems","item","add","value1","value2","sub","times","div","compareTo","eq","lt","lte","gt","gte","round","rm","toString","toNumber","result","formatBytes","bytes","units","i"],"mappings":"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"}
@@ -1,232 +0,0 @@
1
- import { Decimal as u, ROUNDING_MODE as a } from "./decimal.js";
2
- const S = new u("-9223372036854775808"), h = new u("9223372036854775807"), w = new RegExp("([+-]?)([0-9]*)[.]?([0-9]*)"), $ = /^[+-]?(\d+\.?\d*|\.\d+)(e[+-]?\d+)?$/i, d = (n) => typeof n == "string" && n.trim() === "";
3
- function M(n, r) {
4
- if (n == null || d(n))
5
- return !1;
6
- const t = Number.isFinite(r?.minValue) ? new u(r.minValue) : S;
7
- try {
8
- return t.lte(n) && h.gte(n);
9
- } catch {
10
- return !1;
11
- }
12
- }
13
- function p(n, r, t) {
14
- if (n == null || n === "")
15
- return "";
16
- let e;
17
- switch (typeof n) {
18
- case "number":
19
- if (!Number.isFinite(n))
20
- return String(n);
21
- e = new u(n).toString();
22
- break;
23
- case "string":
24
- if (e = g(n).trim(), !$.test(e))
25
- return n;
26
- /e/i.test(e) && (e = `${e.startsWith("+") ? "+" : ""}${new u(e).toString()}`);
27
- break;
28
- default:
29
- e = n.toString();
30
- }
31
- const i = w.exec(e), f = i[1];
32
- let o = i[2] || "0", c = i[3], l, m = new u(`${f === "-" ? "-" : ""}${o}.${c}`);
33
- if (r != null) {
34
- m = m.round(r, t ?? a.roundHalfUp);
35
- const N = w.exec(m.toString());
36
- o = N[2], c = N[3], l = r;
37
- } else
38
- l = c.length;
39
- const b = m.eq(0) ? "" : f;
40
- return o = o.replace(/(\d)(?=(\d{3})+$)/g, "$1,"), c = `${c}${"0".repeat(l)}`.substring(0, l), c === "" ? `${b}${o}` : `${b}${o}.${c}`;
41
- }
42
- function g(n) {
43
- return n.replace(/,/g, "");
44
- }
45
- function _(n, r) {
46
- return new Intl.NumberFormat(r, { notation: "compact" }).format(n);
47
- }
48
- function T(n, r, t) {
49
- let e = new u(n);
50
- for (const i of r)
51
- e = e[i.operator](i.value);
52
- return t?.scale != null && (e = e.round(t.scale, t.roundingMode ?? a.roundHalfUp)), e.toNumber();
53
- }
54
- function U(n, ...r) {
55
- let t = new u(n);
56
- for (const e of r)
57
- t = t.add(e);
58
- return t.toNumber();
59
- }
60
- function k(n, ...r) {
61
- let t = new u(n);
62
- for (const e of r)
63
- t = t.sub(e);
64
- return t.toNumber();
65
- }
66
- function B(n, ...r) {
67
- let t = new u(n);
68
- for (const e of r)
69
- t = t.times(e);
70
- return t.toNumber();
71
- }
72
- function y(n, ...r) {
73
- let t = new u(n);
74
- for (const e of r)
75
- t = t.div(e);
76
- return t.toNumber();
77
- }
78
- function s(n, r) {
79
- return new u(n).compareTo(r);
80
- }
81
- function R(n, r) {
82
- return s(n, r) === 0;
83
- }
84
- function E(n, r) {
85
- return s(n, r) < 0;
86
- }
87
- function F(n, r) {
88
- return s(n, r) <= 0;
89
- }
90
- function O(n, r) {
91
- return 0 < s(n, r);
92
- }
93
- function V(n, r) {
94
- return 0 <= s(n, r);
95
- }
96
- function x(n, r, t) {
97
- if (n == null)
98
- return null;
99
- const e = t ?? a.roundHalfUp;
100
- switch (typeof n) {
101
- case "number":
102
- return Number.isFinite(n) ? new u(n).round(r, e).toNumber() : n;
103
- case "string": {
104
- if (d(n))
105
- return null;
106
- try {
107
- return new u(n).round(r, e).toNumber();
108
- } catch {
109
- return Number.NaN;
110
- }
111
- }
112
- default:
113
- return new u(n).round(r, e).toNumber();
114
- }
115
- }
116
- function G(n, r) {
117
- if (n == null)
118
- return "";
119
- if (d(n) || typeof n == "number" && !Number.isFinite(n))
120
- return String(n);
121
- try {
122
- const t = new u(n);
123
- return r?.scale != null ? t.toFixed(r.scale, r.roundingMode ?? a.roundHalfUp) : t.toString();
124
- } catch {
125
- return String(n);
126
- }
127
- }
128
- function H(n, r) {
129
- if (n == null || d(n))
130
- switch (r?.empty) {
131
- case "undefined":
132
- return;
133
- case "zero":
134
- return 0;
135
- default:
136
- return null;
137
- }
138
- let t;
139
- switch (typeof n) {
140
- case "number":
141
- t = n;
142
- break;
143
- case "bigint":
144
- t = Number(n);
145
- break;
146
- default:
147
- t = Number(g(n).trim());
148
- }
149
- if (Number.isNaN(t))
150
- switch (r?.nan) {
151
- case "null":
152
- return null;
153
- case "undefined":
154
- return;
155
- default:
156
- return t;
157
- }
158
- return t;
159
- }
160
- function I(n, r) {
161
- if (n == null || n === "")
162
- return [String(n), ""];
163
- let t;
164
- switch (typeof n) {
165
- case "number":
166
- if (Number.isNaN(n))
167
- return ["NaN", ""];
168
- t = new u(n);
169
- break;
170
- case "string":
171
- try {
172
- t = new u(g(n));
173
- } catch {
174
- return [n, ""];
175
- }
176
- break;
177
- default:
178
- t = new u(n);
179
- }
180
- const e = ["B", "KB", "MB", "GB", "TB"];
181
- let i = 0;
182
- for (; t.gte(1024) && i < e.length - 1; )
183
- t = t.div(1024), i++;
184
- const f = r?.scale ?? 2, o = r?.roundingMode ?? a.roundHalfUp;
185
- return r?.format ? [p(t.toString(), f, o), e[i]] : [t.round(f, o).toString(), e[i]];
186
- }
187
- const j = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
188
- __proto__: null,
189
- ROUNDING_MODE: a,
190
- add: U,
191
- calc: T,
192
- compareTo: s,
193
- div: y,
194
- eq: R,
195
- formatBytes: I,
196
- formatComma: p,
197
- formatCompact: _,
198
- gt: O,
199
- gte: V,
200
- isLongValue: M,
201
- lt: E,
202
- lte: F,
203
- removeComma: g,
204
- round: x,
205
- sub: k,
206
- times: B,
207
- toNumber: H,
208
- toString: G
209
- }, Symbol.toStringTag, { value: "Module" }));
210
- export {
211
- U as a,
212
- s as b,
213
- T as c,
214
- y as d,
215
- R as e,
216
- I as f,
217
- p as g,
218
- _ as h,
219
- O as i,
220
- V as j,
221
- M as k,
222
- E as l,
223
- F as m,
224
- j as n,
225
- x as o,
226
- H as p,
227
- G as q,
228
- g as r,
229
- k as s,
230
- B as t
231
- };
232
- //# sourceMappingURL=number-util-Wpubbqr4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"number-util-Wpubbqr4.js","sources":["../src/number-util.ts"],"sourcesContent":["import { Decimal, ROUNDING_MODE } from './decimal';\nimport type { NumberSource, RoundingMode } from './decimal';\n\nexport { ROUNDING_MODE };\nexport type { NumberSource, RoundingMode };\n\n// 64bit整数の範囲\nconst MIN_LONG = new Decimal('-9223372036854775808');\nconst MAX_LONG = new Decimal('9223372036854775807');\n\n/** 数値パターン */\nconst NUMBER_PATTERN = new RegExp('([\\+\\-]?)([0-9]*)[\\.]?([0-9]*)');\n\n/** 数値として解釈できる文字列のパターン(符号・小数点・指数表記) */\nconst NUMERIC_STRING_PATTERN = /^[+-]?(\\d+\\.?\\d*|\\.\\d+)(e[+-]?\\d+)?$/i;\n\n// 空文字・空白のみの文字列はtrueを返す\nconst isBlank = (value: unknown): value is string => typeof value === 'string' && value.trim() === '';\n\n/**\n * long(64bit)の範囲(-9223372036854775808〜9223372036854775807)の値か判定する\n * Javascriptのnumberの範囲は(-9007199254740991〜9007199254740991)である\n *\n * @param {string | bigint} value\n * @param {*} [options]\n * ├ minValue number 最小値を指定する場合(0を指定すると負数の場合falseを返す)\n * 不正な値を指定した場合は無視される(最小値を-9223372036854775808とみなす)\n * @returns {boolean}\n * @see Number.MAX_SAFE_INTEGER\n * @see Number.MIN_SAFE_INTEGER\n */\nexport function isLongValue(value: string | bigint, options?: {\n minValue?: number;\n}): boolean {\n if (value == null || isBlank(value)) {\n return false;\n }\n const min = Number.isFinite(options?.minValue) ? new Decimal(options!.minValue) : MIN_LONG;\n try {\n // -9223372036854775808 <= value <= 9223372036854775807\n return min.lte(value) && MAX_LONG.gte(value);\n } catch (error) {\n // 数値として解釈できない値\n return false;\n }\n}\n\n/**\n * 3桁ごとカンマ区切りした文字列を返す\n * 指数表記の値(1e21など)は通常の表記に展開してから区切る\n * 数値として解釈できない文字列はそのまま返し、NaN/Infinityは \"NaN\"/\"Infinity\"/\"-Infinity\" を返す\n *\n * @param {NumberSource | null | undefined} value 値\n * @param {number} [scale] 小数点桁数(補助桁数)\n * @param {RoundingMode} [roundingMode] 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * @returns {string}\n */\nexport function formatComma(value: NumberSource | null | undefined, scale?: number, roundingMode?: RoundingMode): string {\n if (value == null || value === '') {\n // 空文字を返却\n return '';\n }\n let strValue: string;\n switch (typeof value) {\n case 'number':\n if (!Number.isFinite(value)) {\n // \"NaN\" / \"Infinity\" / \"-Infinity\" を返却\n return String(value);\n }\n // toString()は1e21以上や1e-7以下を指数表記にするため、Decimalで通常の表記に展開する\n strValue = new Decimal(value).toString();\n break;\n case 'string':\n strValue = removeComma(value).trim();\n if (!NUMERIC_STRING_PATTERN.test(strValue)) {\n // 元の文字列を返却\n return value;\n }\n if (/e/i.test(strValue)) {\n // 指数表記を通常の表記に展開する。表示用に '+' を付け直す\n const plusSign = strValue.startsWith('+') ? '+' : '';\n strValue = `${plusSign}${new Decimal(strValue).toString()}`;\n }\n break;\n default:\n // bigintの場合\n strValue = value.toString();\n }\n const matches = NUMBER_PATTERN.exec(strValue) as RegExpExecArray;\n const sign = matches[1];\n let natural = matches[2] || '0';\n let decimal = matches[3];\n let dp: number;\n let decimalValue = new Decimal(`${sign === '-' ? '-' : ''}${natural}.${decimal}`);\n if (scale != null) {\n decimalValue = decimalValue.round(scale, roundingMode ?? ROUNDING_MODE.roundHalfUp);\n const roundedMatches = NUMBER_PATTERN.exec(decimalValue.toString()) as RegExpExecArray;\n natural = roundedMatches[2];\n decimal = roundedMatches[3];\n dp = scale;\n } else {\n dp = decimal.length;\n }\n // 丸めた結果がゼロになる場合('-0.001' を小数2桁にするなど)に \"-0.00\" とならないよう、丸めた後の値で判定する\n const displaySign = decimalValue.eq(0) ? '' : sign;\n natural = natural.replace(/(\\d)(?=(\\d{3})+$)/g, '$1,');\n decimal = `${decimal}${'0'.repeat(dp)}`.substring(0, dp);\n return decimal === ''\n ? `${displaySign}${natural}`\n : `${displaySign}${natural}.${decimal}`;\n}\n\n/**\n * カンマを除去する\n *\n * @param {string} value 入力値\n * @returns {string} カンマを取り除いた文字列\n */\nexport function removeComma(value: string): string {\n return value.replace(/,/g, '');\n}\n\n/**\n * 数値を表示ロケールの短縮表記にする。\n * en は 1.2K/3.4M/5.6B、ja は 12万/34億 のように単位が切り替わる。\n *\n * @param {number} value 値\n * @param {string} locale 表示ロケール(例 'ja' / 'en')\n * @returns {string} 短縮表記の文字列\n */\nexport function formatCompact(value: number, locale: string): string {\n return new Intl.NumberFormat(locale, { notation: 'compact' }).format(value);\n}\n\nexport type Operator = 'add' | 'sub' | 'times' | 'div';\n\nexport interface OperationItem {\n operator: Operator;\n value: NumberSource | null | undefined;\n}\n\n/**\n * 複数の演算をまとめて計算する\n * 計算途中は精度を保持し、最後にnumberへ変換する\n * この関数では四則演算の優先順位はなく、与えられた配列の順で計算を行う\n * * 優先順位やカッコの概念がある場合は事前に計算したうえでこの関数を利用する\n *\n * 例)\n * calc(\n * '123',\n * [\n * { operator: 'add', value: '123' },\n * { operator: 'sub', value: 100 },\n * { operator: 'times', value: 2 },\n * { operator: 'div', value: 3 }\n * ]\n * )\n * 123 + 123 = 246\n * 246 - 100 = 146\n * 146 * 2 = 292\n * 292 / 3 = 97.33333333\n *\n * null等の扱いは add / sub / times / div と同じ\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} initialValue\n * @param {OperationItem[]} operationItems\n * ├ operator: Operator\n * ├ value: NumberSource | null | undefined\n * @param {*} [options]\n * ├ scale 計算結果を丸める小数桁数。指定しない場合は丸めない\n * ├ roundingMode 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * @returns {number}\n */\nexport function calc(initialValue: NumberSource | null | undefined, operationItems: OperationItem[], options?: {\n scale?: number;\n roundingMode?: RoundingMode;\n}): number {\n let decimal = new Decimal(initialValue);\n for (const item of operationItems) {\n decimal = decimal[item.operator](item.value);\n }\n if (options?.scale != null) {\n decimal = decimal.round(options.scale, options.roundingMode ?? ROUNDING_MODE.roundHalfUp);\n }\n return decimal.toNumber();\n}\n\n/**\n * 加算を行う\n * null/undefined/空文字/NaNは0と見做されるため、演算結果に影響しない\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function add(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.add(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 減算を行う\n * null/undefined/空文字/NaNは0と見做されるため、演算結果に影響しない\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function sub(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.sub(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 乗算を行う\n * null/undefined/空文字/NaNは0と見做されるため、演算結果は0になる\n * 元の値を保持したい場合は times(price, discount ?? 1) のようにフォールバック値を指定する\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function times(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.times(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 除算を行う\n * 割る値のnull/undefined/空文字/NaNは1と見做されるため、演算結果に影響しない\n * 割る値に0を指定した場合はゼロ除算エラーになる\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {(NumberSource | null | undefined)[]} value2\n * @returns {number}\n */\nexport function div(value1: NumberSource | null | undefined, ...value2: (NumberSource | null | undefined)[]): number {\n let decimal = new Decimal(value1);\n for (const value of value2) {\n decimal = decimal.div(value);\n }\n return decimal.toNumber();\n}\n\n/**\n * 2つの値を数値として比較する\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {-1 | 0 | 1} value1がvalue2より小さい場合は-1、等しい場合は0、大きい場合は1\n */\nexport function compareTo(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): -1 | 0 | 1 {\n return new Decimal(value1).compareTo(value2);\n}\n\n/**\n * 2つの値が数値として等しいかを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function eq(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return compareTo(value1, value2) === 0;\n}\n\n/**\n * value1がvalue2より小さいかを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function lt(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return compareTo(value1, value2) < 0;\n}\n\n/**\n * value1がvalue2以下かを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function lte(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return compareTo(value1, value2) <= 0;\n}\n\n/**\n * value1がvalue2より大きいかを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function gt(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return 0 < compareTo(value1, value2);\n}\n\n/**\n * value1がvalue2以上かを返す\n * null/undefined/空文字/NaNは0と見做す\n * 数値として解釈できない文字列やInfinityを指定した場合はTypeErrorになる\n *\n * @param {NumberSource | null | undefined} value1\n * @param {NumberSource | null | undefined} value2\n * @returns {boolean}\n */\nexport function gte(value1: NumberSource | null | undefined, value2: NumberSource | null | undefined): boolean {\n return 0 <= compareTo(value1, value2);\n}\n\n/**\n * 数値を指定した桁で丸める\n * null/undefined/空文字はnull、数値として解釈できない文字列はNaNを返す\n * NaN/Infinityはそのまま返す\n * 戻り値はnumberのため、Number.MAX_SAFE_INTEGERを超える結果は精度が落ちる\n *\n * @param {NumberSource | null | undefined} value\n * @param {number} scale\n * @param {RoundingMode} [roundingMode] デフォルトは 1: 四捨五入\n * 0 切り捨て\n * 1 四捨五入\n * 2 ISO丸め\n * 3 切り上げ\n * @returns {number | null}\n * @see ROUNDING_MODE\n */\nexport function round(\n value: NumberSource | null | undefined,\n scale: number,\n roundingMode?: RoundingMode\n): number | null {\n if (value == null) {\n return null;\n }\n const rm = roundingMode ?? ROUNDING_MODE.roundHalfUp;\n switch (typeof value) {\n case 'number':\n if (!Number.isFinite(value)) {\n // NaN/Infinityはそのまま返す\n return value;\n }\n return new Decimal(value).round(scale, rm).toNumber();\n case 'string': {\n if (isBlank(value)) {\n // 空文字は値なしとしてnullと同じ扱いにする\n return null;\n }\n try {\n return new Decimal(value).round(scale, rm).toNumber();\n } catch (error) {\n // 数値として解釈できない文字列\n return Number.NaN;\n }\n }\n default:\n return new Decimal(value).round(scale, rm).toNumber();\n }\n}\n\n/**\n * 数値文字列に変換する\n * 指数表記にはならず、通常の表記で返す\n * 数値として解釈できない値はString(value)を返す\n *\n * @param {NumberSource | null | undefined} value\n * @param {*} [options]\n * ├ scale 小数桁数。指定しない場合は丸めずにすべての桁を返す\n * ├ roundingMode 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * @returns {string}\n * @see ROUNDING_MODE\n */\nexport function toString(\n value: NumberSource | null | undefined,\n options?: {\n scale?: number;\n roundingMode?: RoundingMode;\n }\n): string {\n if (value == null) {\n return '';\n }\n if (isBlank(value) || (typeof value === 'number' && !Number.isFinite(value))) {\n // 空文字・NaN・Infinityは数値として扱わない\n return String(value);\n }\n try {\n const decimal = new Decimal(value);\n return options?.scale != null\n ? decimal.toFixed(options.scale, options.roundingMode ?? ROUNDING_MODE.roundHalfUp)\n : decimal.toString();\n } catch (error) {\n return String(value);\n }\n}\n\n/** toNumber のオプション */\nexport interface ToNumberOptions {\n /** 未指定(null・undefined・空白のみの文字列)のときに返す値。デフォルトは 'null' */\n empty?: 'null' | 'undefined' | 'zero';\n /** 数値として解釈できない(結果が NaN になる)ときに返す値。デフォルトは 'NaN' */\n nan?: 'NaN' | 'null' | 'undefined';\n}\n\n/** options.empty に応じた未指定時の戻り値の型。'zero' は number に含まれるので never */\ntype EmptyResult<O extends ToNumberOptions> = O extends { empty?: infer E }\n ? E extends 'undefined' ? undefined : E extends 'zero' ? never : null\n : null;\n\n/** options.nan に応じた変換不可時の戻り値の型。'NaN' は number に含まれるので never */\ntype NanResult<O extends ToNumberOptions> = O extends { nan?: infer N }\n ? N extends 'null' ? null : N extends 'undefined' ? undefined : never\n : never;\n\n/**\n * 数値に変換する\n * 文字列はカンマと前後の空白を除いてから変換する\n * null・undefined・空白のみの文字列は未指定として扱い、options.empty に応じて null(デフォルト)・undefined・0 のいずれかを返す\n * 数値として解釈できない場合は options.nan に応じて NaN(デフォルト)・null・undefined のいずれかを返す\n *\n * @param {NumberSource | null | undefined} value\n * @param {ToNumberOptions} [options]\n * ├ empty 未指定のときに返す値。'null'(デフォルト) | 'undefined' | 'zero'\n * └ nan 数値として解釈できないときに返す値。'NaN'(デフォルト) | 'null' | 'undefined'\n * @returns {number | EmptyResult<O> | NanResult<O>} 戻り値の型は options に連動する\n */\nexport function toNumber<O extends ToNumberOptions = Record<never, never>>(value: NumberSource | null | undefined, options?: O): number | EmptyResult<O> | NanResult<O> {\n type Result = number | EmptyResult<O> | NanResult<O>;\n if (value == null || isBlank(value)) {\n switch (options?.empty) {\n case 'undefined':\n return undefined as Result;\n case 'zero':\n return 0;\n default:\n return null as Result;\n }\n }\n let result: number;\n switch (typeof value) {\n case 'number':\n result = value;\n break;\n case 'bigint':\n result = Number(value);\n break;\n default:\n result = Number(removeComma(value).trim());\n }\n if (Number.isNaN(result)) {\n switch (options?.nan) {\n case 'null':\n return null as Result;\n case 'undefined':\n return undefined as Result;\n default:\n return result;\n }\n }\n return result;\n}\n\n/**\n * 渡されたバイト数値を桁数に応じてMB,GBなどに単位を変更する\n *\n * @param {NumberSource} bytes\n * @param {*} [options]\n * ┝ scale 小数以下桁数 デフォルト:2\n * ┝ roundingMode 丸めモード デフォルトはROUNDING_MODE.roundHalfUp(四捨五入・half-away-from-zero)\n * ┝ format フォーマットするか。trueを指定した場合、3桁カンマ区切り+小数末尾0の桁揃え\n * @returns {[string, string]} 精度以下を丸めた数値(文字列)と単位をタプルで返す\n */\nexport function formatBytes(\n bytes: NumberSource,\n options?: {\n scale?: number;\n roundingMode?: RoundingMode;\n format?: boolean;\n }\n): [string, string] {\n if (bytes == null || bytes === '') {\n return [String(bytes), ''];\n }\n let decimalValue: Decimal;\n switch (typeof bytes) {\n case 'number':\n if (Number.isNaN(bytes)) {\n // \"NaN\" を返却\n return ['NaN', ''];\n }\n decimalValue = new Decimal(bytes);\n break;\n case 'string':\n try {\n decimalValue = new Decimal(removeComma(bytes));\n } catch (error) {\n // 元の文字列を返却\n return [bytes, ''];\n }\n break;\n default:\n // bigintの場合\n decimalValue = new Decimal(bytes);\n }\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n let i = 0;\n while (decimalValue.gte(1024) && i < units.length - 1) {\n decimalValue = decimalValue.div(1024);\n i++;\n }\n const scale = options?.scale ?? 2;\n const roundingMode = options?.roundingMode ?? ROUNDING_MODE.roundHalfUp;\n if (options?.format) {\n return [formatComma(decimalValue.toString(), scale, roundingMode), units[i]];\n }\n return [decimalValue.round(scale, roundingMode).toString(), units[i]];\n}\n"],"names":["MIN_LONG","Decimal","MAX_LONG","NUMBER_PATTERN","NUMERIC_STRING_PATTERN","isBlank","value","isLongValue","options","min","formatComma","scale","roundingMode","strValue","removeComma","matches","sign","natural","decimal","dp","decimalValue","ROUNDING_MODE","roundedMatches","displaySign","formatCompact","locale","calc","initialValue","operationItems","item","add","value1","value2","sub","times","div","compareTo","eq","lt","lte","gt","gte","round","rm","toString","toNumber","result","formatBytes","bytes","units"],"mappings":"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"}