@scale-sense/core 0.1.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,141 @@
1
+ declare const SOURCE_KINDS: readonly ["westernNumeric", "westernWords", "chineseGrouped", "chineseWords", "digitalWords"];
2
+ type SourceKind = (typeof SOURCE_KINDS)[number];
3
+ declare const CONVERSION_CARD_KINDS: readonly ["bitToByte", "byteToBit", "twdToUsd", "usdToTwd"];
4
+ type ConversionCardKind = (typeof CONVERSION_CARD_KINDS)[number];
5
+ declare const SAVE_TARGET_KINDS: readonly ["westernNumeric", "westernWords", "chineseGrouped", "chineseWords", "digitalWords", "bitToByte", "byteToBit", "twdToUsd", "usdToTwd"];
6
+ type SaveTargetKind = (typeof SAVE_TARGET_KINDS)[number];
7
+ declare const SAVE_UNIT_PRESETS: readonly ["台幣", "美金", "人", "bit", "Byte"];
8
+ declare const CONVERSION_AUTO_UNITS: Record<ConversionCardKind, string>;
9
+ declare function isConversionTargetKind(kind: SaveTargetKind): kind is ConversionCardKind;
10
+ type ParseOutcome = {
11
+ kind: 'ok';
12
+ value: bigint;
13
+ } | {
14
+ kind: 'incomplete';
15
+ } | {
16
+ kind: 'error';
17
+ message: string;
18
+ };
19
+ type PipelineStatus = 'empty' | 'incomplete' | 'error' | 'ok';
20
+ declare const SOURCE_LABELS: Record<SourceKind, string>;
21
+ declare const CONVERSION_CARD_LABELS: Record<ConversionCardKind, string>;
22
+
23
+ declare const HISTORY_JSON_VERSION: 3;
24
+ declare const SUPPORTED_HISTORY_JSON_VERSIONS: readonly [2, 3];
25
+ type HistorySortMode = 'time-desc' | 'time-asc' | 'value-desc' | 'value-asc';
26
+ declare const HISTORY_SORT_MODES: HistorySortMode[];
27
+ declare const HISTORY_SORT_LABELS: Record<HistorySortMode, string>;
28
+ type HistoryEntry = {
29
+ id: string;
30
+ savedAt: number;
31
+ standardValue: string;
32
+ sourceKind: SourceKind;
33
+ sourceRaw: string;
34
+ sourceNumeric: string;
35
+ targetKind: SaveTargetKind;
36
+ targetValue: string;
37
+ targetUnit: string | null;
38
+ note: string;
39
+ tags: string[];
40
+ };
41
+ type HistoryBackupFile = {
42
+ version: typeof HISTORY_JSON_VERSION;
43
+ exportedAt: string;
44
+ entries: HistoryEntry[];
45
+ };
46
+ declare function parseHistorySortMode(value: unknown): HistorySortMode;
47
+ declare function normalizeTagLabel(name: string): string | null;
48
+ declare function collectAllTags(entries: HistoryEntry[]): string[];
49
+ declare function filterHistoryByTags(entries: HistoryEntry[], selectedTags: string[]): HistoryEntry[];
50
+ declare function getEntryIdsWithTag(entries: HistoryEntry[], tagName: string): string[];
51
+ declare function applyTagMembership(entries: HistoryEntry[], tagName: string, entryIds: string[]): HistoryEntry[];
52
+ declare function parseHistoryEntry(item: unknown): HistoryEntry | null;
53
+ declare function sortHistoryEntries(entries: HistoryEntry[], mode: HistorySortMode): HistoryEntry[];
54
+ /** History list source column: western numeric shows standardized digits; others show raw input. */
55
+ declare function historySourceDisplay(e: HistoryEntry): string;
56
+ /** History list target column card label. */
57
+ declare function historyTargetKindLabel(kind: SaveTargetKind): string;
58
+ declare function historyToCsvRows(entries: HistoryEntry[]): string;
59
+ /** UTF-8 with BOM for Excel */
60
+ declare function csvBlobUtf8Bom(csv: string): Blob;
61
+ declare function buildBackupPayload(entries: HistoryEntry[]): HistoryBackupFile;
62
+ declare function stringifyBackup(payload: HistoryBackupFile): string;
63
+ type ImportHistoryResult = {
64
+ ok: true;
65
+ entries: HistoryEntry[];
66
+ } | {
67
+ ok: false;
68
+ message: string;
69
+ };
70
+ declare function parseBackupJson(text: string): ImportHistoryResult;
71
+
72
+ declare const APP_SETTINGS_JSON_VERSION: 1;
73
+ declare const APP_SETTINGS_KIND: "scale-sense-app-settings";
74
+ type AppSettingsSnapshot = {
75
+ sourceKind: SourceKind;
76
+ rawInput: string;
77
+ cardHidden: Record<SourceKind, boolean>;
78
+ conversionCardHidden: Record<ConversionCardKind, boolean>;
79
+ historySortMode: HistorySortMode;
80
+ savedCustomUnits: string[];
81
+ };
82
+ type AppSettingsBackupFile = {
83
+ kind: typeof APP_SETTINGS_KIND;
84
+ version: typeof APP_SETTINGS_JSON_VERSION;
85
+ exportedAt: string;
86
+ settings: AppSettingsSnapshot;
87
+ };
88
+ declare function parseAppSettingsSnapshot(value: unknown): AppSettingsSnapshot | null;
89
+ declare function buildAppSettingsPayload(settings: AppSettingsSnapshot): AppSettingsBackupFile;
90
+ declare function stringifyAppSettingsBackup(payload: AppSettingsBackupFile): string;
91
+ type ImportAppSettingsResult = {
92
+ ok: true;
93
+ settings: AppSettingsSnapshot;
94
+ } | {
95
+ ok: false;
96
+ message: string;
97
+ };
98
+ declare function parseAppSettingsBackup(text: string): ImportAppSettingsResult;
99
+
100
+ type ChartKind = 'bar' | 'barHorizontal' | 'scatter';
101
+ declare const CHART_KIND_LABELS: Record<ChartKind, string>;
102
+ type ChartPoint = {
103
+ id: string;
104
+ order: number;
105
+ value: number | null;
106
+ valueLabel: string;
107
+ shortLabel: string;
108
+ entry: HistoryEntry;
109
+ };
110
+ declare function buildChartPoints(entries: HistoryEntry[]): ChartPoint[];
111
+ declare function canUseLogScale(points: ChartPoint[]): boolean;
112
+ /** Recharts log axes default to a domain that includes 0 and breaks rendering; set an explicit positive lower bound. */
113
+ declare function computeLogValueDomain(points: ChartPoint[]): [number, 'auto'];
114
+ declare function horizontalBarChartHeight(pointCount: number): number;
115
+
116
+ declare function formatWesternNumericValue(n: bigint): string;
117
+ declare function formatValueAsKind(n: bigint, kind: SourceKind): string;
118
+ type ConversionCardView = {
119
+ source: string;
120
+ target: string;
121
+ };
122
+ /** Extract the numeric portion from a conversion card target string (e.g. `96 byte`). */
123
+ declare function conversionTargetNumeric(target: string): string;
124
+ declare function formatConversionCard(value: bigint, kind: ConversionCardKind): ConversionCardView;
125
+
126
+ declare function parseByKind(kind: SourceKind, raw: string): ParseOutcome;
127
+
128
+ type PipelineResult = {
129
+ status: PipelineStatus;
130
+ /** User-facing message when status is error */
131
+ errorMessage?: string;
132
+ standardValue: bigint | null;
133
+ /** Formatted value per card; use '--' when not shown in UI layer */
134
+ formattedByKind: Record<SourceKind, string>;
135
+ };
136
+ declare function runPipeline(sourceKind: SourceKind, rawInput: string): PipelineResult;
137
+
138
+ declare function normalizeUnitLabel(unit: string): string;
139
+ declare function shouldRememberCustomUnit(unit: string, savedCustomUnits: readonly string[]): boolean;
140
+
141
+ export { APP_SETTINGS_JSON_VERSION, APP_SETTINGS_KIND, type AppSettingsBackupFile, type AppSettingsSnapshot, CHART_KIND_LABELS, CONVERSION_AUTO_UNITS, CONVERSION_CARD_KINDS, CONVERSION_CARD_LABELS, type ChartKind, type ChartPoint, type ConversionCardKind, HISTORY_JSON_VERSION, HISTORY_SORT_LABELS, HISTORY_SORT_MODES, type HistoryEntry, type HistorySortMode, type ImportAppSettingsResult, type ParseOutcome, type PipelineResult, type PipelineStatus, SAVE_TARGET_KINDS, SAVE_UNIT_PRESETS, SOURCE_KINDS, SOURCE_LABELS, SUPPORTED_HISTORY_JSON_VERSIONS, type SaveTargetKind, type SourceKind, applyTagMembership, buildAppSettingsPayload, buildBackupPayload, buildChartPoints, canUseLogScale, collectAllTags, computeLogValueDomain, conversionTargetNumeric, csvBlobUtf8Bom, filterHistoryByTags, formatConversionCard, formatValueAsKind, formatWesternNumericValue, getEntryIdsWithTag, historySourceDisplay, historyTargetKindLabel, historyToCsvRows, horizontalBarChartHeight, isConversionTargetKind, normalizeTagLabel, normalizeUnitLabel, parseAppSettingsBackup, parseAppSettingsSnapshot, parseBackupJson, parseByKind, parseHistoryEntry, parseHistorySortMode, runPipeline, shouldRememberCustomUnit, sortHistoryEntries, stringifyAppSettingsBackup, stringifyBackup };
package/dist/index.js ADDED
@@ -0,0 +1,1013 @@
1
+ // src/types.ts
2
+ var SOURCE_KINDS = [
3
+ "westernNumeric",
4
+ "westernWords",
5
+ "chineseGrouped",
6
+ "chineseWords",
7
+ "digitalWords"
8
+ ];
9
+ var CONVERSION_CARD_KINDS = [
10
+ "bitToByte",
11
+ "byteToBit",
12
+ "twdToUsd",
13
+ "usdToTwd"
14
+ ];
15
+ var SAVE_TARGET_KINDS = [
16
+ ...SOURCE_KINDS,
17
+ ...CONVERSION_CARD_KINDS
18
+ ];
19
+ var SAVE_UNIT_PRESETS = ["\u53F0\u5E63", "\u7F8E\u91D1", "\u4EBA", "bit", "Byte"];
20
+ var CONVERSION_AUTO_UNITS = {
21
+ bitToByte: "Byte",
22
+ byteToBit: "bit",
23
+ twdToUsd: "\u7F8E\u91D1",
24
+ usdToTwd: "\u53F0\u5E63"
25
+ };
26
+ function isConversionTargetKind(kind) {
27
+ return CONVERSION_CARD_KINDS.includes(kind);
28
+ }
29
+ var SOURCE_LABELS = {
30
+ westernNumeric: "\u82F1\u7F8E\u6578\u5B57",
31
+ westernWords: "\u82F1\u6587\u8A9E\u8A00",
32
+ chineseGrouped: "\u4E2D\u6587\u6578\u5B57\uFF08\u56DB\u4F4D\u5206\u7BC0\uFF09",
33
+ chineseWords: "\u4E2D\u6587\u8A9E\u8A00",
34
+ digitalWords: "Digital \u8A9E\u8A00"
35
+ };
36
+ var CONVERSION_CARD_LABELS = {
37
+ bitToByte: "bit \u8F49 byte",
38
+ byteToBit: "byte \u8F49 bit",
39
+ twdToUsd: "\u53F0\u5E63\u8F49\u7F8E\u91D1",
40
+ usdToTwd: "\u7F8E\u91D1\u8F49\u53F0\u5E63"
41
+ };
42
+
43
+ // src/history.ts
44
+ var HISTORY_JSON_VERSION = 3;
45
+ var SUPPORTED_HISTORY_JSON_VERSIONS = [2, 3];
46
+ var HISTORY_SORT_MODES = [
47
+ "time-desc",
48
+ "time-asc",
49
+ "value-desc",
50
+ "value-asc"
51
+ ];
52
+ var HISTORY_SORT_LABELS = {
53
+ "time-desc": "\u6642\u9593\uFF08\u65B0\u5230\u820A\uFF09",
54
+ "time-asc": "\u6642\u9593\uFF08\u820A\u5230\u65B0\uFF09",
55
+ "value-desc": "\u6578\u503C\uFF08\u5927\u5230\u5C0F\uFF09",
56
+ "value-asc": "\u6578\u503C\uFF08\u5C0F\u5230\u5927\uFF09"
57
+ };
58
+ var WESTERN_NUMERIC_SOURCE_KINDS = ["westernNumeric"];
59
+ function isValidSourceKind(k) {
60
+ return SOURCE_KINDS.includes(k);
61
+ }
62
+ function isValidSaveTargetKind(k) {
63
+ return SAVE_TARGET_KINDS.includes(k);
64
+ }
65
+ function parseStandardValue(value) {
66
+ try {
67
+ return BigInt(value);
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+ function isValidHistorySortMode(value) {
73
+ return HISTORY_SORT_MODES.includes(value);
74
+ }
75
+ function parseHistorySortMode(value) {
76
+ if (typeof value === "string" && isValidHistorySortMode(value)) {
77
+ return value;
78
+ }
79
+ return "time-desc";
80
+ }
81
+ function normalizeTagLabel(name) {
82
+ const trimmed = name.trim();
83
+ return trimmed.length > 0 ? trimmed : null;
84
+ }
85
+ function parseTagsField(value) {
86
+ if (value === void 0) return [];
87
+ if (!Array.isArray(value)) return null;
88
+ const tags = [];
89
+ for (const item of value) {
90
+ if (typeof item !== "string") return null;
91
+ const normalized = normalizeTagLabel(item);
92
+ if (!normalized) return null;
93
+ if (!tags.includes(normalized)) tags.push(normalized);
94
+ }
95
+ return tags;
96
+ }
97
+ function collectAllTags(entries) {
98
+ const seen = /* @__PURE__ */ new Set();
99
+ const out = [];
100
+ for (const entry of entries) {
101
+ for (const tag of entry.tags) {
102
+ if (!seen.has(tag)) {
103
+ seen.add(tag);
104
+ out.push(tag);
105
+ }
106
+ }
107
+ }
108
+ return out.sort((a, b) => a.localeCompare(b, "zh-Hant"));
109
+ }
110
+ function filterHistoryByTags(entries, selectedTags) {
111
+ if (selectedTags.length === 0) return entries;
112
+ return entries.filter(
113
+ (entry) => selectedTags.some((tag) => entry.tags.includes(tag))
114
+ );
115
+ }
116
+ function getEntryIdsWithTag(entries, tagName) {
117
+ return entries.filter((e) => e.tags.includes(tagName)).map((e) => e.id);
118
+ }
119
+ function applyTagMembership(entries, tagName, entryIds) {
120
+ const idSet = new Set(entryIds);
121
+ return entries.map((entry) => {
122
+ const hasTag = entry.tags.includes(tagName);
123
+ const shouldHave = idSet.has(entry.id);
124
+ if (shouldHave && !hasTag) {
125
+ return { ...entry, tags: [...entry.tags, tagName] };
126
+ }
127
+ if (!shouldHave && hasTag) {
128
+ return { ...entry, tags: entry.tags.filter((t) => t !== tagName) };
129
+ }
130
+ return entry;
131
+ });
132
+ }
133
+ function parseHistoryEntry(item) {
134
+ if (!item || typeof item !== "object") return null;
135
+ const e = item;
136
+ if (typeof e.id !== "string" || typeof e.savedAt !== "number" || typeof e.standardValue !== "string" || parseStandardValue(e.standardValue) === null || typeof e.sourceKind !== "string" || !isValidSourceKind(e.sourceKind) || typeof e.sourceRaw !== "string" || typeof e.sourceNumeric !== "string" || typeof e.targetKind !== "string" || !isValidSaveTargetKind(e.targetKind) || typeof e.targetValue !== "string" || e.targetUnit !== null && typeof e.targetUnit !== "string" || typeof e.note !== "string") {
137
+ return null;
138
+ }
139
+ const tags = parseTagsField(e.tags);
140
+ if (tags === null) return null;
141
+ return {
142
+ id: e.id,
143
+ savedAt: e.savedAt,
144
+ standardValue: e.standardValue,
145
+ sourceKind: e.sourceKind,
146
+ sourceRaw: e.sourceRaw,
147
+ sourceNumeric: e.sourceNumeric,
148
+ targetKind: e.targetKind,
149
+ targetValue: e.targetValue,
150
+ targetUnit: e.targetUnit,
151
+ note: e.note,
152
+ tags
153
+ };
154
+ }
155
+ function compareBySavedAtDesc(a, b) {
156
+ return b.savedAt - a.savedAt;
157
+ }
158
+ function compareByStandardValue(a, b, direction) {
159
+ const av = BigInt(a.standardValue);
160
+ const bv = BigInt(b.standardValue);
161
+ if (av < bv) return direction === "asc" ? -1 : 1;
162
+ if (av > bv) return direction === "asc" ? 1 : -1;
163
+ return compareBySavedAtDesc(a, b);
164
+ }
165
+ function sortHistoryEntries(entries, mode) {
166
+ const copy = [...entries];
167
+ switch (mode) {
168
+ case "time-desc":
169
+ return copy.sort((a, b) => b.savedAt - a.savedAt);
170
+ case "time-asc":
171
+ return copy.sort((a, b) => a.savedAt - b.savedAt);
172
+ case "value-desc":
173
+ return copy.sort((a, b) => compareByStandardValue(a, b, "desc"));
174
+ case "value-asc":
175
+ return copy.sort((a, b) => compareByStandardValue(a, b, "asc"));
176
+ }
177
+ }
178
+ function historySourceDisplay(e) {
179
+ if (WESTERN_NUMERIC_SOURCE_KINDS.includes(
180
+ e.sourceKind
181
+ )) {
182
+ return e.sourceNumeric;
183
+ }
184
+ return e.sourceRaw;
185
+ }
186
+ function historyTargetKindLabel(kind) {
187
+ if (isConversionTargetKind(kind)) {
188
+ return CONVERSION_CARD_LABELS[kind];
189
+ }
190
+ return SOURCE_LABELS[kind];
191
+ }
192
+ var CSV_HEADER = [
193
+ "\u6642\u9593",
194
+ "\u4F86\u6E90\u985E\u578B",
195
+ "\u4F86\u6E90\u539F\u59CB\u5167\u5BB9",
196
+ "\u4F86\u6E90\u6A19\u6E96\u5316\u6578\u5B57",
197
+ "\u5132\u5B58\u76EE\u6A19",
198
+ "\u76EE\u6A19\u6578\u503C",
199
+ "\u76EE\u6A19\u55AE\u4F4D",
200
+ "\u7B46\u8A18",
201
+ "\u6A19\u7C64"
202
+ ];
203
+ function historyToCsvRows(entries) {
204
+ const lines = [CSV_HEADER];
205
+ const sorted = sortHistoryEntries(entries, "time-desc");
206
+ for (const e of sorted) {
207
+ const t = new Date(e.savedAt).toISOString();
208
+ lines.push([
209
+ t,
210
+ e.sourceKind,
211
+ e.sourceRaw,
212
+ e.sourceNumeric,
213
+ e.targetKind,
214
+ e.targetValue,
215
+ e.targetUnit ?? "",
216
+ e.note,
217
+ e.tags.join(";")
218
+ ]);
219
+ }
220
+ return lines.map((row) => row.map(escapeCsvCell).join(",")).join("\r\n");
221
+ }
222
+ function escapeCsvCell(s) {
223
+ if (/[",\r\n]/.test(s)) return `"${s.replace(/"/g, '""')}"`;
224
+ return s;
225
+ }
226
+ function csvBlobUtf8Bom(csv) {
227
+ const bom = new Uint8Array([239, 187, 191]);
228
+ return new Blob([bom, csv], { type: "text/csv;charset=utf-8" });
229
+ }
230
+ function buildBackupPayload(entries) {
231
+ return {
232
+ version: HISTORY_JSON_VERSION,
233
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
234
+ entries
235
+ };
236
+ }
237
+ function stringifyBackup(payload) {
238
+ return `${JSON.stringify(payload, null, 2)}
239
+ `;
240
+ }
241
+ function parseBackupJson(text) {
242
+ let data;
243
+ try {
244
+ data = JSON.parse(text);
245
+ } catch {
246
+ return { ok: false, message: "JSON \u683C\u5F0F\u7121\u6CD5\u89E3\u6790" };
247
+ }
248
+ if (!data || typeof data !== "object") {
249
+ return { ok: false, message: "\u5099\u4EFD\u6A94\u5167\u5BB9\u4E0D\u662F\u7269\u4EF6" };
250
+ }
251
+ const rec = data;
252
+ if (!SUPPORTED_HISTORY_JSON_VERSIONS.includes(
253
+ rec.version
254
+ )) {
255
+ return { ok: false, message: `\u4E0D\u652F\u63F4\u7684\u7248\u672C\uFF1A${String(rec.version)}` };
256
+ }
257
+ if (!Array.isArray(rec.entries)) {
258
+ return { ok: false, message: "\u7F3A\u5C11 entries \u9663\u5217" };
259
+ }
260
+ const out = [];
261
+ for (const item of rec.entries) {
262
+ const entry = parseHistoryEntry(item);
263
+ if (!entry) {
264
+ return { ok: false, message: "\u7D00\u9304\u6B04\u4F4D\u4E0D\u5B8C\u6574\u6216\u578B\u5225\u4E0D\u6B63\u78BA" };
265
+ }
266
+ out.push(entry);
267
+ }
268
+ return { ok: true, entries: out };
269
+ }
270
+
271
+ // src/app-settings.ts
272
+ var APP_SETTINGS_JSON_VERSION = 1;
273
+ var APP_SETTINGS_KIND = "scale-sense-app-settings";
274
+ function isValidSourceKind2(k) {
275
+ return SOURCE_KINDS.includes(k);
276
+ }
277
+ function parseCardHidden(value) {
278
+ if (!value || typeof value !== "object") return null;
279
+ const rec = value;
280
+ const out = {};
281
+ for (const kind of SOURCE_KINDS) {
282
+ if (typeof rec[kind] !== "boolean") return null;
283
+ out[kind] = rec[kind];
284
+ }
285
+ return out;
286
+ }
287
+ function parseConversionCardHidden(value) {
288
+ if (!value || typeof value !== "object") return null;
289
+ const rec = value;
290
+ const out = {};
291
+ for (const kind of CONVERSION_CARD_KINDS) {
292
+ if (typeof rec[kind] !== "boolean") return null;
293
+ out[kind] = rec[kind];
294
+ }
295
+ return out;
296
+ }
297
+ function parseSavedCustomUnits(value) {
298
+ if (!Array.isArray(value)) return null;
299
+ if (!value.every((u) => typeof u === "string")) return null;
300
+ return value;
301
+ }
302
+ function parseAppSettingsSnapshot(value) {
303
+ if (!value || typeof value !== "object") return null;
304
+ const rec = value;
305
+ if (typeof rec.sourceKind !== "string" || !isValidSourceKind2(rec.sourceKind)) {
306
+ return null;
307
+ }
308
+ if (typeof rec.rawInput !== "string") return null;
309
+ const cardHidden = parseCardHidden(rec.cardHidden);
310
+ if (!cardHidden) return null;
311
+ const conversionCardHidden = parseConversionCardHidden(
312
+ rec.conversionCardHidden
313
+ );
314
+ if (!conversionCardHidden) return null;
315
+ const savedCustomUnits = parseSavedCustomUnits(rec.savedCustomUnits);
316
+ if (!savedCustomUnits) return null;
317
+ return {
318
+ sourceKind: rec.sourceKind,
319
+ rawInput: rec.rawInput,
320
+ cardHidden,
321
+ conversionCardHidden,
322
+ historySortMode: parseHistorySortMode(rec.historySortMode),
323
+ savedCustomUnits
324
+ };
325
+ }
326
+ function buildAppSettingsPayload(settings) {
327
+ return {
328
+ kind: APP_SETTINGS_KIND,
329
+ version: APP_SETTINGS_JSON_VERSION,
330
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
331
+ settings
332
+ };
333
+ }
334
+ function stringifyAppSettingsBackup(payload) {
335
+ return `${JSON.stringify(payload, null, 2)}
336
+ `;
337
+ }
338
+ function parseAppSettingsBackup(text) {
339
+ let data;
340
+ try {
341
+ data = JSON.parse(text);
342
+ } catch {
343
+ return { ok: false, message: "JSON \u683C\u5F0F\u7121\u6CD5\u89E3\u6790" };
344
+ }
345
+ if (!data || typeof data !== "object") {
346
+ return { ok: false, message: "\u5099\u4EFD\u6A94\u5167\u5BB9\u4E0D\u662F\u7269\u4EF6" };
347
+ }
348
+ const rec = data;
349
+ if (rec.kind !== APP_SETTINGS_KIND && SUPPORTED_HISTORY_JSON_VERSIONS.includes(
350
+ rec.version
351
+ ) && Array.isArray(rec.entries)) {
352
+ return {
353
+ ok: false,
354
+ message: "\u6B64\u6A94\u70BA\u6B77\u53F2\u5099\u4EFD\uFF0C\u8ACB\u81F3\u6536\u85CF\u9801\u532F\u5165"
355
+ };
356
+ }
357
+ if (rec.kind !== APP_SETTINGS_KIND) {
358
+ return { ok: false, message: "\u4E0D\u662F\u6709\u6548\u7684\u8A2D\u5B9A\u5099\u4EFD\u6A94" };
359
+ }
360
+ if (rec.version !== APP_SETTINGS_JSON_VERSION) {
361
+ return { ok: false, message: `\u4E0D\u652F\u63F4\u7684\u7248\u672C\uFF1A${String(rec.version)}` };
362
+ }
363
+ const settings = parseAppSettingsSnapshot(rec.settings);
364
+ if (!settings) {
365
+ return { ok: false, message: "\u8A2D\u5B9A\u6B04\u4F4D\u4E0D\u5B8C\u6574\u6216\u578B\u5225\u4E0D\u6B63\u78BA" };
366
+ }
367
+ return { ok: true, settings };
368
+ }
369
+
370
+ // src/format.ts
371
+ var DIGITS_CN = [
372
+ "\u96F6",
373
+ "\u4E00",
374
+ "\u4E8C",
375
+ "\u4E09",
376
+ "\u56DB",
377
+ "\u4E94",
378
+ "\u516D",
379
+ "\u4E03",
380
+ "\u516B",
381
+ "\u4E5D"
382
+ ];
383
+ function formatWesternNumericValue(n) {
384
+ if (n === 0n) return "0";
385
+ const neg = n < 0n;
386
+ const v = neg ? -n : n;
387
+ const s = v.toString();
388
+ const parts = [];
389
+ for (let i = s.length; i > 0; i -= 3) {
390
+ const start = Math.max(0, i - 3);
391
+ parts.push(s.slice(start, i));
392
+ }
393
+ const out = parts.reverse().join(",");
394
+ return neg ? `-${out}` : out;
395
+ }
396
+ var NAMES_UNDER_20 = [
397
+ "zero",
398
+ "one",
399
+ "two",
400
+ "three",
401
+ "four",
402
+ "five",
403
+ "six",
404
+ "seven",
405
+ "eight",
406
+ "nine",
407
+ "ten",
408
+ "eleven",
409
+ "twelve",
410
+ "thirteen",
411
+ "fourteen",
412
+ "fifteen",
413
+ "sixteen",
414
+ "seventeen",
415
+ "eighteen",
416
+ "nineteen"
417
+ ];
418
+ var TENS = [
419
+ "",
420
+ "",
421
+ "twenty",
422
+ "thirty",
423
+ "forty",
424
+ "fifty",
425
+ "sixty",
426
+ "seventy",
427
+ "eighty",
428
+ "ninety"
429
+ ];
430
+ function underThousandEnglish(n) {
431
+ if (n === 0) return "";
432
+ if (n < 20) return NAMES_UNDER_20[n];
433
+ if (n < 100) {
434
+ const t = Math.floor(n / 10);
435
+ const o = n % 10;
436
+ return o ? `${TENS[t]}-${underThousandEnglish(o)}` : TENS[t];
437
+ }
438
+ const h = Math.floor(n / 100);
439
+ const rest = n % 100;
440
+ const head = `${NAMES_UNDER_20[h]} hundred`;
441
+ return rest ? `${head} ${underThousandEnglish(rest)}` : head;
442
+ }
443
+ function formatWesternWordsValue(n) {
444
+ if (n === 0n) return "zero";
445
+ const neg = n < 0n;
446
+ let v = neg ? -n : n;
447
+ if (v > 1000000000000000n) {
448
+ return `${formatWesternNumericValue(n)} (\u8D85\u51FA\u53EF\u8F49\u63DB\u70BA\u82F1\u6587\u8A9E\u610F\u7684\u7BC4\u570D)`;
449
+ }
450
+ const scales = [
451
+ { name: "trillion", value: 1000000000000n },
452
+ { name: "billion", value: 1000000000n },
453
+ { name: "million", value: 1000000n },
454
+ { name: "thousand", value: 1000n }
455
+ ];
456
+ const parts = [];
457
+ for (const { name, value } of scales) {
458
+ if (v >= value) {
459
+ const c = Number(v / value);
460
+ v %= value;
461
+ parts.push(`${underThousandEnglish(c)} ${name}`.trim());
462
+ }
463
+ }
464
+ if (v > 0n) {
465
+ parts.push(underThousandEnglish(Number(v)));
466
+ }
467
+ const core = parts.join(" ").replace(/\s+/g, " ").trim();
468
+ return neg ? `negative ${core}` : core;
469
+ }
470
+ function fourDigitToCn(n) {
471
+ if (n === 0) return "";
472
+ const q = Math.floor(n / 1e3);
473
+ const b = Math.floor(n % 1e3 / 100);
474
+ const s = Math.floor(n % 100 / 10);
475
+ const o = n % 10;
476
+ let out = "";
477
+ if (q > 0) out += `${DIGITS_CN[q]}\u5343`;
478
+ if (b > 0) out += `${DIGITS_CN[b]}\u767E`;
479
+ else if (q > 0 && (s > 0 || o > 0)) out += "\u96F6";
480
+ if (s > 0) out += `${DIGITS_CN[s]}\u5341`;
481
+ else if (b > 0 && o > 0) out += "\u96F6";
482
+ if (o > 0) out += DIGITS_CN[o];
483
+ return out;
484
+ }
485
+ function formatChineseGroupedValue(n) {
486
+ if (n === 0n) return "0";
487
+ const neg = n < 0n;
488
+ let v = neg ? -n : n;
489
+ const groups = [];
490
+ while (v > 0n) {
491
+ const g = Number(v % 10000n);
492
+ groups.push(g);
493
+ v /= 10000n;
494
+ }
495
+ const normalizedGroups = groups.reverse().map(
496
+ (group, idx) => idx === 0 ? String(group) : String(group).padStart(4, "0")
497
+ );
498
+ const body = normalizedGroups.join(",");
499
+ return neg ? `-${body}` : body;
500
+ }
501
+ function formatChineseWordsValue(n) {
502
+ if (n === 0n) return "\u96F6";
503
+ const neg = n < 0n;
504
+ let v = neg ? -n : n;
505
+ if (v >= 1000000000000000n) {
506
+ return `${formatWesternNumericValue(n)}\uFF08\u6578\u503C\u904E\u5927\uFF0C\u4E2D\u6587\u8A9E\u610F\u986F\u793A\u70BA\u7C21\u5316\u5F62\u5F0F\uFF09`;
507
+ }
508
+ const \u5146 = 1000000000000n;
509
+ const \u5104 = 100000000n;
510
+ const \u842C = 10000n;
511
+ const parts = [];
512
+ const zhao = v / \u5146;
513
+ if (zhao > 0n) {
514
+ parts.push(`${fourDigitToCn(Number(zhao))}\u5146`.replace(/^一十/, "\u5341"));
515
+ v %= \u5146;
516
+ }
517
+ const yi = v / \u5104;
518
+ if (yi > 0n) {
519
+ parts.push(`${fourDigitToCn(Number(yi))}\u5104`.replace(/^一十/, "\u5341"));
520
+ v %= \u5104;
521
+ }
522
+ const wan = v / \u842C;
523
+ if (wan > 0n) {
524
+ parts.push(`${fourDigitToCn(Number(wan))}\u842C`.replace(/^一十/, "\u5341"));
525
+ v %= \u842C;
526
+ }
527
+ if (v > 0n) {
528
+ parts.push(fourDigitToCn(Number(v)));
529
+ }
530
+ const core = parts.join("").replace(/零+/g, "\u96F6").replace(/零$/, "");
531
+ const out = core || "\u96F6";
532
+ return neg ? `\u8CA0${out}` : out;
533
+ }
534
+ function formatDigitalWordsValue(n) {
535
+ return formatWesternNumericValue(n);
536
+ }
537
+ function formatValueAsKind(n, kind) {
538
+ switch (kind) {
539
+ case "westernNumeric":
540
+ return formatWesternNumericValue(n);
541
+ case "westernWords":
542
+ return formatWesternWordsValue(n);
543
+ case "chineseGrouped":
544
+ return formatChineseGroupedValue(n);
545
+ case "chineseWords":
546
+ return formatChineseWordsValue(n);
547
+ case "digitalWords":
548
+ return formatDigitalWordsValue(n);
549
+ default:
550
+ return "";
551
+ }
552
+ }
553
+ var USD_RATE_DEN = 32n;
554
+ function formatDecimalRatio(numerator, denominator, maxFractionDigits = 6) {
555
+ const intPart = numerator / denominator;
556
+ let remainder = numerator % denominator;
557
+ const intText = formatWesternNumericValue(intPart);
558
+ if (remainder === 0n) return intText;
559
+ let fraction = "";
560
+ for (let i = 0; i < maxFractionDigits && remainder !== 0n; i++) {
561
+ remainder *= 10n;
562
+ fraction += (remainder / denominator).toString();
563
+ remainder %= denominator;
564
+ }
565
+ fraction = fraction.replace(/0+$/, "");
566
+ return fraction ? `${intText}.${fraction}` : intText;
567
+ }
568
+ function conversionTargetNumeric(target) {
569
+ const m = target.match(/^(.+)\s+[A-Za-z]+$/);
570
+ return m ? m[1] : target;
571
+ }
572
+ function formatConversionCard(value, kind) {
573
+ switch (kind) {
574
+ case "bitToByte":
575
+ return {
576
+ source: `${formatWesternNumericValue(value)} bit`,
577
+ target: `${formatDecimalRatio(value, 8n)} byte`
578
+ };
579
+ case "byteToBit":
580
+ return {
581
+ source: `${formatWesternNumericValue(value)} byte`,
582
+ target: `${formatWesternNumericValue(value * 8n)} bit`
583
+ };
584
+ case "twdToUsd":
585
+ return {
586
+ source: `${formatWesternNumericValue(value)} TWD`,
587
+ target: `${formatDecimalRatio(value, USD_RATE_DEN)} USD`
588
+ };
589
+ case "usdToTwd":
590
+ return {
591
+ source: `${formatWesternNumericValue(value)} USD`,
592
+ target: `${formatWesternNumericValue(value * USD_RATE_DEN)} TWD`
593
+ };
594
+ default:
595
+ return { source: "-", target: "-" };
596
+ }
597
+ }
598
+
599
+ // src/chart.ts
600
+ var CHART_KIND_LABELS = {
601
+ bar: "\u9577\u689D\u5716",
602
+ barHorizontal: "\u6A6B\u5411\u9577\u689D\u5716",
603
+ scatter: "\u6563\u9EDE\u5716"
604
+ };
605
+ function truncateNoteLabel(note, order) {
606
+ const trimmed = note.trim();
607
+ if (trimmed.length === 0) return `#${order}`;
608
+ return [...trimmed].slice(0, 2).join("");
609
+ }
610
+ function toChartNumeric(standardValue) {
611
+ const parsed = parseStandardValue(standardValue);
612
+ if (parsed === null) return null;
613
+ if (parsed <= 0n) return null;
614
+ const n = Number(parsed);
615
+ if (!Number.isFinite(n) || n <= 0) return null;
616
+ return n;
617
+ }
618
+ function buildChartPoints(entries) {
619
+ return entries.map((entry, index) => {
620
+ const order = index + 1;
621
+ const parsed = parseStandardValue(entry.standardValue);
622
+ const valueLabel = parsed !== null ? formatWesternNumericValue(parsed) : entry.standardValue;
623
+ return {
624
+ id: entry.id,
625
+ order,
626
+ value: toChartNumeric(entry.standardValue),
627
+ valueLabel,
628
+ shortLabel: truncateNoteLabel(entry.note, order),
629
+ entry
630
+ };
631
+ });
632
+ }
633
+ function canUseLogScale(points) {
634
+ if (points.length === 0) return false;
635
+ return points.every((p) => p.value !== null && p.value > 0);
636
+ }
637
+ function computeLogValueDomain(points) {
638
+ const values = points.map((p) => p.value).filter((v) => v !== null && v > 0);
639
+ if (values.length === 0) return [1, "auto"];
640
+ const min = Math.min(...values);
641
+ return [min * 0.5, "auto"];
642
+ }
643
+ var HORIZONTAL_BAR_ROW_HEIGHT = 36;
644
+ var HORIZONTAL_BAR_CHART_PADDING = 40;
645
+ var MIN_CHART_HEIGHT = 192;
646
+ function horizontalBarChartHeight(pointCount) {
647
+ if (pointCount <= 0) return MIN_CHART_HEIGHT;
648
+ return Math.max(
649
+ MIN_CHART_HEIGHT,
650
+ pointCount * HORIZONTAL_BAR_ROW_HEIGHT + HORIZONTAL_BAR_CHART_PADDING
651
+ );
652
+ }
653
+
654
+ // src/digital.ts
655
+ var DECIMAL_KB = 1000n;
656
+ var DECIMAL_MB = 1000000n;
657
+ var DECIMAL_GB = 1000000000n;
658
+ var DECIMAL_TB = 1000000000000n;
659
+ var DECIMAL_PB = 1000000000000000n;
660
+ var DECIMAL_BY_UNIT = {
661
+ k: DECIMAL_KB,
662
+ m: DECIMAL_MB,
663
+ g: DECIMAL_GB,
664
+ t: DECIMAL_TB,
665
+ p: DECIMAL_PB
666
+ };
667
+ function digitalUnitToScalar(unit) {
668
+ return DECIMAL_BY_UNIT[unit];
669
+ }
670
+
671
+ // src/parse.ts
672
+ var WS = /\s+/;
673
+ var UNITS_EN = {
674
+ thousand: 1000n,
675
+ million: 1000000n,
676
+ billion: 1000000000n,
677
+ trillion: 1000000000000n
678
+ };
679
+ var UNIT_PREFIXES = ["thousand", "million", "billion", "trillion"];
680
+ function isIncompleteEnglishUnitToken(s) {
681
+ const t = s.toLowerCase();
682
+ if (UNITS_EN[t] !== void 0) return false;
683
+ return UNIT_PREFIXES.some((u) => u.startsWith(t) && t.length > 0);
684
+ }
685
+ function parseDigitToken(raw) {
686
+ const cleaned = raw.replace(/,/g, "");
687
+ if (!/^\d+$/.test(cleaned)) return null;
688
+ return BigInt(cleaned);
689
+ }
690
+ function parseWesternNumeric(raw) {
691
+ const s = raw.trim();
692
+ if (s.length === 0) return { kind: "error", message: "\u8ACB\u8F38\u5165\u6578\u5B57" };
693
+ const cleaned = s.replace(/,/g, "").replace(/\s+/g, "");
694
+ if (!/^\d+$/.test(cleaned)) {
695
+ if (/^\d*$/.test(cleaned) && cleaned.length > 0)
696
+ return { kind: "incomplete" };
697
+ return { kind: "error", message: "\u50C5\u652F\u63F4\u6574\u6578\u8207\u5343\u5206\u4F4D\u9017\u865F" };
698
+ }
699
+ return { kind: "ok", value: BigInt(cleaned) };
700
+ }
701
+ function parseWesternWords(raw) {
702
+ const s = raw.trim().toLowerCase();
703
+ if (s.length === 0) return { kind: "error", message: "\u8ACB\u8F38\u5165\u82F1\u6587\u6578\u5B57\u8A9E\u610F" };
704
+ const tokens = s.split(WS).filter(Boolean);
705
+ if (tokens.length === 0)
706
+ return { kind: "error", message: "\u8ACB\u8F38\u5165\u82F1\u6587\u6578\u5B57\u8A9E\u610F" };
707
+ if (tokens.length === 1 && UNITS_EN[tokens[0]] !== void 0) {
708
+ return { kind: "error", message: "\u55AE\u4F4D\u524D\u9700\u6709\u6578\u5B57" };
709
+ }
710
+ let sum = 0n;
711
+ let current = 0n;
712
+ let expectingNumber = true;
713
+ for (const tok of tokens) {
714
+ const mult = UNITS_EN[tok];
715
+ if (mult !== void 0) {
716
+ if (expectingNumber && tokens.indexOf(tok) === 0) {
717
+ return { kind: "error", message: "\u55AE\u4F4D\u524D\u9700\u6709\u6578\u5B57" };
718
+ }
719
+ sum += current * mult;
720
+ current = 0n;
721
+ expectingNumber = true;
722
+ continue;
723
+ }
724
+ const n = parseDigitToken(tok);
725
+ if (n !== null) {
726
+ current = n;
727
+ expectingNumber = false;
728
+ continue;
729
+ }
730
+ if (isIncompleteEnglishUnitToken(tok)) return { kind: "incomplete" };
731
+ return { kind: "error", message: "\u7121\u6CD5\u8FA8\u8B58\u7684\u82F1\u6587\u55AE\u4F4D\u6216\u6578\u5B57" };
732
+ }
733
+ if (expectingNumber && tokens.length > 0) {
734
+ const last = tokens[tokens.length - 1];
735
+ if (isIncompleteEnglishUnitToken(last)) return { kind: "incomplete" };
736
+ }
737
+ sum += current;
738
+ return { kind: "ok", value: sum };
739
+ }
740
+ function parseChineseGrouped(raw) {
741
+ const s = raw.trim();
742
+ if (s.length === 0) return { kind: "error", message: "\u8ACB\u8F38\u5165\u4E2D\u6587\u5206\u7BC0\u6578\u5B57" };
743
+ const parts = s.split(",").map((p) => p.trim());
744
+ if (parts.some((p) => p.length === 0)) return { kind: "incomplete" };
745
+ for (const p of parts) {
746
+ if (!/^\d{1,4}$/.test(p)) {
747
+ if (/^\d*$/.test(p) && p.length > 0 && p.length <= 4)
748
+ return { kind: "incomplete" };
749
+ return { kind: "error", message: "\u6BCF\u6BB5\u9700\u70BA 1\u20134 \u4F4D\u6578\u5B57" };
750
+ }
751
+ }
752
+ const n = parts.length;
753
+ let total = 0n;
754
+ for (let i = 0; i < n; i++) {
755
+ const g = BigInt(parts[i]);
756
+ const exp = BigInt(n - 1 - i) * 4n;
757
+ total += g * 10n ** exp;
758
+ }
759
+ return { kind: "ok", value: total };
760
+ }
761
+ var CN_UNITS = {
762
+ \u842C: 10000n,
763
+ \u5104: 100000000n,
764
+ \u5146: 1000000000000n
765
+ };
766
+ var CN_UNIT_ORDER = {
767
+ \u5146: 3,
768
+ \u5104: 2,
769
+ \u842C: 1
770
+ };
771
+ function pow10(exp) {
772
+ return 10n ** BigInt(exp);
773
+ }
774
+ function parseChineseCoeff(token, unit) {
775
+ if (!/^\d+(?:\.\d+)?$/.test(token)) {
776
+ return { kind: "error", message: "\u4E2D\u6587\u8A9E\u610F\u4FC2\u6578\u683C\u5F0F\u4E0D\u6B63\u78BA" };
777
+ }
778
+ if (!token.includes(".")) {
779
+ const base = BigInt(token);
780
+ return { kind: "ok", value: unit ? base * CN_UNITS[unit] : base };
781
+ }
782
+ if (!unit) {
783
+ return { kind: "error", message: "\u5C0F\u6578\u9700\u642D\u914D\u842C\uFF0F\u5104\uFF0F\u5146\u55AE\u4F4D" };
784
+ }
785
+ const [intPart, fracPart] = token.split(".");
786
+ if (!fracPart || fracPart.length === 0) return { kind: "incomplete" };
787
+ if (fracPart.length > 4) {
788
+ return { kind: "error", message: "\u5C0F\u6578\u4F4D\u6578\u6700\u591A 4 \u4F4D" };
789
+ }
790
+ const scaled = BigInt(`${intPart}${fracPart}`);
791
+ const scale = pow10(fracPart.length);
792
+ const numer = scaled * CN_UNITS[unit];
793
+ if (numer % scale !== 0n) {
794
+ return { kind: "error", message: "\u5C0F\u6578\u7121\u6CD5\u7CBE\u78BA\u63DB\u7B97\u70BA\u6574\u6578" };
795
+ }
796
+ return { kind: "ok", value: numer / scale };
797
+ }
798
+ function parseChineseWords(raw) {
799
+ const s = raw.trim().replace(/\s+/g, "");
800
+ if (s.length === 0) return { kind: "error", message: "\u8ACB\u8F38\u5165\u4E2D\u6587\u8A9E\u610F\u6578\u5B57" };
801
+ if (!/^[\d.萬億兆]+$/.test(s)) {
802
+ return { kind: "error", message: "\u50C5\u652F\u63F4\u6578\u5B57\u3001\u5C0F\u6578\u9EDE\u8207\u842C\uFF0F\u5104\uFF0F\u5146" };
803
+ }
804
+ if (/^\d+\.\d{0,4}$/.test(s)) return { kind: "incomplete" };
805
+ let total = 0n;
806
+ let cursor = 0;
807
+ let lastOrder = Number.POSITIVE_INFINITY;
808
+ let seenUnit = false;
809
+ let hasTail = false;
810
+ while (cursor < s.length) {
811
+ const tokenMatch = s.slice(cursor).match(/^(\d+(?:\.\d+)?)/);
812
+ if (!tokenMatch) {
813
+ return { kind: "error", message: "\u4E2D\u6587\u8A9E\u610F\u683C\u5F0F\u4E0D\u6B63\u78BA" };
814
+ }
815
+ const coeff = tokenMatch[1];
816
+ cursor += coeff.length;
817
+ const next = s[cursor] ?? "";
818
+ const hasUnit = next === "\u5146" || next === "\u5104" || next === "\u842C";
819
+ if (hasTail && (hasUnit || coeff.length > 0)) {
820
+ return { kind: "error", message: "\u5C3E\u6BB5\u6578\u5B57\u5F8C\u4E0D\u53EF\u518D\u63A5\u65B0\u7247\u6BB5" };
821
+ }
822
+ if (hasUnit) {
823
+ const unit = next;
824
+ const order = CN_UNIT_ORDER[unit];
825
+ if (order >= lastOrder) {
826
+ return { kind: "error", message: "\u4E2D\u6587\u55AE\u4F4D\u9700\u7531\u5927\u5230\u5C0F\u4E14\u4E0D\u53EF\u91CD\u8907" };
827
+ }
828
+ const parsed = parseChineseCoeff(coeff, unit);
829
+ if (parsed.kind !== "ok") return parsed;
830
+ total += parsed.value;
831
+ seenUnit = true;
832
+ lastOrder = order;
833
+ cursor += 1;
834
+ continue;
835
+ }
836
+ if (coeff.includes(".")) {
837
+ return { kind: "error", message: "\u5C0F\u6578\u9700\u642D\u914D\u842C\uFF0F\u5104\uFF0F\u5146\u55AE\u4F4D" };
838
+ }
839
+ const parsedTail = parseChineseCoeff(coeff, null);
840
+ if (parsedTail.kind !== "ok") return parsedTail;
841
+ total += parsedTail.value;
842
+ hasTail = seenUnit;
843
+ if (cursor < s.length) {
844
+ return { kind: "error", message: "\u4E2D\u6587\u8A9E\u610F\u683C\u5F0F\u4E0D\u6B63\u78BA" };
845
+ }
846
+ }
847
+ return { kind: "ok", value: total };
848
+ }
849
+ var DIG_WORDS = {
850
+ kilo: "k",
851
+ kilobyte: "k",
852
+ kilobytes: "k",
853
+ k: "k",
854
+ mega: "m",
855
+ megabyte: "m",
856
+ megabytes: "m",
857
+ m: "m",
858
+ giga: "g",
859
+ gigabyte: "g",
860
+ gigabytes: "g",
861
+ g: "g",
862
+ tera: "t",
863
+ terabyte: "t",
864
+ terabytes: "t",
865
+ t: "t",
866
+ peta: "p",
867
+ petabyte: "p",
868
+ petabytes: "p",
869
+ p: "p"
870
+ };
871
+ function parseDigitalWords(raw) {
872
+ const s = raw.trim().toLowerCase();
873
+ if (s.length === 0)
874
+ return { kind: "error", message: "\u8ACB\u8F38\u5165 Digital \u8A9E\u610F\uFF08\u5982 1 giga \u6216 1 G\uFF09" };
875
+ const m = s.match(/^([\d,]+)\s*([a-z]+)\s*$/);
876
+ if (!m) {
877
+ if (/^[\d,]*$/.test(s)) return { kind: "incomplete" };
878
+ return {
879
+ kind: "error",
880
+ message: "\u683C\u5F0F\u61C9\u70BA\u300C\u6578\u5B57 + \u55AE\u4F4D\uFF08\u5982 kilo\u3001G\uFF09\u300D"
881
+ };
882
+ }
883
+ const num = parseDigitToken(m[1]);
884
+ if (num === null) return { kind: "error", message: "\u6578\u5B57\u683C\u5F0F\u4E0D\u6B63\u78BA" };
885
+ const unitKey = m[2];
886
+ const kind = DIG_WORDS[unitKey];
887
+ if (!kind) {
888
+ const partial = Object.keys(DIG_WORDS).some(
889
+ (k) => k.startsWith(unitKey) && unitKey.length > 0
890
+ );
891
+ if (partial) return { kind: "incomplete" };
892
+ return {
893
+ kind: "error",
894
+ message: "\u50C5\u652F\u63F4 kilo\uFF0Fmega\uFF0Fgiga\uFF0Ftera\uFF0Fpeta\uFF08\u6216 K\uFF0FM\uFF0FG\uFF0FT\uFF0FP\uFF09"
895
+ };
896
+ }
897
+ const mult = digitalUnitToScalar(kind);
898
+ return { kind: "ok", value: num * mult };
899
+ }
900
+ function parseByKind(kind, raw) {
901
+ const trimmed = raw.trim();
902
+ if (trimmed.length === 0) return { kind: "error", message: "\u8ACB\u8F38\u5165\u5167\u5BB9" };
903
+ switch (kind) {
904
+ case "westernNumeric":
905
+ return parseWesternNumeric(raw);
906
+ case "westernWords":
907
+ return parseWesternWords(raw);
908
+ case "chineseGrouped":
909
+ return parseChineseGrouped(raw);
910
+ case "chineseWords":
911
+ return parseChineseWords(raw);
912
+ case "digitalWords":
913
+ return parseDigitalWords(raw);
914
+ default:
915
+ return { kind: "error", message: "\u672A\u77E5\u6B04\u4F4D" };
916
+ }
917
+ }
918
+
919
+ // src/pipeline.ts
920
+ function runPipeline(sourceKind, rawInput) {
921
+ const empty = makeEmptyOutputs();
922
+ const trimmed = rawInput.trim();
923
+ if (trimmed.length === 0) {
924
+ return { status: "empty", standardValue: null, formattedByKind: empty };
925
+ }
926
+ const outcome = parseByKind(sourceKind, rawInput);
927
+ if (outcome.kind === "incomplete") {
928
+ return { status: "incomplete", standardValue: null, formattedByKind: empty };
929
+ }
930
+ if (outcome.kind === "error") {
931
+ return {
932
+ status: "error",
933
+ errorMessage: outcome.message,
934
+ standardValue: null,
935
+ formattedByKind: empty
936
+ };
937
+ }
938
+ const v = outcome.value;
939
+ const formattedByKind = {};
940
+ for (const k of SOURCE_KINDS) {
941
+ formattedByKind[k] = formatValueAsKind(v, k);
942
+ }
943
+ return { status: "ok", standardValue: v, formattedByKind };
944
+ }
945
+ function makeEmptyOutputs() {
946
+ const o = {};
947
+ for (const k of SOURCE_KINDS) o[k] = "";
948
+ return o;
949
+ }
950
+
951
+ // src/units.ts
952
+ function normalizeUnitLabel(unit) {
953
+ return unit.trim();
954
+ }
955
+ function isBuiltInUnit(unit) {
956
+ return SAVE_UNIT_PRESETS.includes(unit);
957
+ }
958
+ function shouldRememberCustomUnit(unit, savedCustomUnits) {
959
+ const normalized = normalizeUnitLabel(unit);
960
+ if (normalized.length === 0) return false;
961
+ if (isBuiltInUnit(normalized)) return false;
962
+ if (savedCustomUnits.includes(normalized)) return false;
963
+ return true;
964
+ }
965
+ export {
966
+ APP_SETTINGS_JSON_VERSION,
967
+ APP_SETTINGS_KIND,
968
+ CHART_KIND_LABELS,
969
+ CONVERSION_AUTO_UNITS,
970
+ CONVERSION_CARD_KINDS,
971
+ CONVERSION_CARD_LABELS,
972
+ HISTORY_JSON_VERSION,
973
+ HISTORY_SORT_LABELS,
974
+ HISTORY_SORT_MODES,
975
+ SAVE_TARGET_KINDS,
976
+ SAVE_UNIT_PRESETS,
977
+ SOURCE_KINDS,
978
+ SOURCE_LABELS,
979
+ SUPPORTED_HISTORY_JSON_VERSIONS,
980
+ applyTagMembership,
981
+ buildAppSettingsPayload,
982
+ buildBackupPayload,
983
+ buildChartPoints,
984
+ canUseLogScale,
985
+ collectAllTags,
986
+ computeLogValueDomain,
987
+ conversionTargetNumeric,
988
+ csvBlobUtf8Bom,
989
+ filterHistoryByTags,
990
+ formatConversionCard,
991
+ formatValueAsKind,
992
+ formatWesternNumericValue,
993
+ getEntryIdsWithTag,
994
+ historySourceDisplay,
995
+ historyTargetKindLabel,
996
+ historyToCsvRows,
997
+ horizontalBarChartHeight,
998
+ isConversionTargetKind,
999
+ normalizeTagLabel,
1000
+ normalizeUnitLabel,
1001
+ parseAppSettingsBackup,
1002
+ parseAppSettingsSnapshot,
1003
+ parseBackupJson,
1004
+ parseByKind,
1005
+ parseHistoryEntry,
1006
+ parseHistorySortMode,
1007
+ runPipeline,
1008
+ shouldRememberCustomUnit,
1009
+ sortHistoryEntries,
1010
+ stringifyAppSettingsBackup,
1011
+ stringifyBackup
1012
+ };
1013
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/history.ts","../src/app-settings.ts","../src/format.ts","../src/chart.ts","../src/digital.ts","../src/parse.ts","../src/pipeline.ts","../src/units.ts"],"sourcesContent":["export const SOURCE_KINDS = [\n 'westernNumeric',\n 'westernWords',\n 'chineseGrouped',\n 'chineseWords',\n 'digitalWords',\n] as const\n\nexport type SourceKind = (typeof SOURCE_KINDS)[number]\n\nexport const CONVERSION_CARD_KINDS = [\n 'bitToByte',\n 'byteToBit',\n 'twdToUsd',\n 'usdToTwd',\n] as const\n\nexport type ConversionCardKind = (typeof CONVERSION_CARD_KINDS)[number]\n\nexport const SAVE_TARGET_KINDS = [\n ...SOURCE_KINDS,\n ...CONVERSION_CARD_KINDS,\n] as const\n\nexport type SaveTargetKind = (typeof SAVE_TARGET_KINDS)[number]\n\nexport const SAVE_UNIT_PRESETS = ['台幣', '美金', '人', 'bit', 'Byte'] as const\n\nexport type SaveUnitPreset = (typeof SAVE_UNIT_PRESETS)[number]\n\nexport const CONVERSION_AUTO_UNITS: Record<ConversionCardKind, string> = {\n bitToByte: 'Byte',\n byteToBit: 'bit',\n twdToUsd: '美金',\n usdToTwd: '台幣',\n}\n\nexport function isConversionTargetKind(\n kind: SaveTargetKind,\n): kind is ConversionCardKind {\n return (CONVERSION_CARD_KINDS as readonly string[]).includes(kind)\n}\n\nexport function isSourceTargetKind(kind: SaveTargetKind): kind is SourceKind {\n return (SOURCE_KINDS as readonly string[]).includes(kind)\n}\n\nexport type ParseOutcome =\n | { kind: 'ok'; value: bigint }\n | { kind: 'incomplete' }\n | { kind: 'error'; message: string }\n\nexport type PipelineStatus = 'empty' | 'incomplete' | 'error' | 'ok'\n\nexport const SOURCE_LABELS: Record<SourceKind, string> = {\n westernNumeric: '英美數字',\n westernWords: '英文語言',\n chineseGrouped: '中文數字(四位分節)',\n chineseWords: '中文語言',\n digitalWords: 'Digital 語言',\n}\n\nexport const CONVERSION_CARD_LABELS: Record<ConversionCardKind, string> = {\n bitToByte: 'bit 轉 byte',\n byteToBit: 'byte 轉 bit',\n twdToUsd: '台幣轉美金',\n usdToTwd: '美金轉台幣',\n}\n","import {\n CONVERSION_CARD_LABELS,\n isConversionTargetKind,\n SAVE_TARGET_KINDS,\n type SaveTargetKind,\n SOURCE_KINDS,\n SOURCE_LABELS,\n type SourceKind,\n} from './types'\n\nexport const HISTORY_JSON_VERSION = 3 as const\n\nexport const SUPPORTED_HISTORY_JSON_VERSIONS = [2, 3] as const\n\nexport type HistorySortMode =\n | 'time-desc'\n | 'time-asc'\n | 'value-desc'\n | 'value-asc'\n\nexport const HISTORY_SORT_MODES: HistorySortMode[] = [\n 'time-desc',\n 'time-asc',\n 'value-desc',\n 'value-asc',\n]\n\nexport const HISTORY_SORT_LABELS: Record<HistorySortMode, string> = {\n 'time-desc': '時間(新到舊)',\n 'time-asc': '時間(舊到新)',\n 'value-desc': '數值(大到小)',\n 'value-asc': '數值(小到大)',\n}\n\nconst WESTERN_NUMERIC_SOURCE_KINDS = ['westernNumeric'] as const\n\nexport type HistoryEntry = {\n id: string\n savedAt: number\n standardValue: string\n sourceKind: SourceKind\n sourceRaw: string\n sourceNumeric: string\n targetKind: SaveTargetKind\n targetValue: string\n targetUnit: string | null\n note: string\n tags: string[]\n}\n\nexport type HistoryBackupFile = {\n version: typeof HISTORY_JSON_VERSION\n exportedAt: string\n entries: HistoryEntry[]\n}\n\nfunction isValidSourceKind(k: string): k is SourceKind {\n return (SOURCE_KINDS as readonly string[]).includes(k)\n}\n\nfunction isValidSaveTargetKind(k: string): k is SaveTargetKind {\n return (SAVE_TARGET_KINDS as readonly string[]).includes(k)\n}\n\nexport function parseStandardValue(value: string): bigint | null {\n try {\n return BigInt(value)\n } catch {\n return null\n }\n}\n\nfunction isValidHistorySortMode(value: string): value is HistorySortMode {\n return (HISTORY_SORT_MODES as readonly string[]).includes(value)\n}\n\nexport function parseHistorySortMode(value: unknown): HistorySortMode {\n if (typeof value === 'string' && isValidHistorySortMode(value)) {\n return value\n }\n return 'time-desc'\n}\n\nexport function normalizeTagLabel(name: string): string | null {\n const trimmed = name.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction parseTagsField(value: unknown): string[] | null {\n if (value === undefined) return []\n if (!Array.isArray(value)) return null\n const tags: string[] = []\n for (const item of value) {\n if (typeof item !== 'string') return null\n const normalized = normalizeTagLabel(item)\n if (!normalized) return null\n if (!tags.includes(normalized)) tags.push(normalized)\n }\n return tags\n}\n\nexport function collectAllTags(entries: HistoryEntry[]): string[] {\n const seen = new Set<string>()\n const out: string[] = []\n for (const entry of entries) {\n for (const tag of entry.tags) {\n if (!seen.has(tag)) {\n seen.add(tag)\n out.push(tag)\n }\n }\n }\n return out.sort((a, b) => a.localeCompare(b, 'zh-Hant'))\n}\n\nexport function filterHistoryByTags(\n entries: HistoryEntry[],\n selectedTags: string[],\n): HistoryEntry[] {\n if (selectedTags.length === 0) return entries\n return entries.filter((entry) =>\n selectedTags.some((tag) => entry.tags.includes(tag)),\n )\n}\n\nexport function getEntryIdsWithTag(\n entries: HistoryEntry[],\n tagName: string,\n): string[] {\n return entries.filter((e) => e.tags.includes(tagName)).map((e) => e.id)\n}\n\nexport function applyTagMembership(\n entries: HistoryEntry[],\n tagName: string,\n entryIds: string[],\n): HistoryEntry[] {\n const idSet = new Set(entryIds)\n return entries.map((entry) => {\n const hasTag = entry.tags.includes(tagName)\n const shouldHave = idSet.has(entry.id)\n if (shouldHave && !hasTag) {\n return { ...entry, tags: [...entry.tags, tagName] }\n }\n if (!shouldHave && hasTag) {\n return { ...entry, tags: entry.tags.filter((t) => t !== tagName) }\n }\n return entry\n })\n}\n\nexport function parseHistoryEntry(item: unknown): HistoryEntry | null {\n if (!item || typeof item !== 'object') return null\n const e = item as Record<string, unknown>\n if (\n typeof e.id !== 'string' ||\n typeof e.savedAt !== 'number' ||\n typeof e.standardValue !== 'string' ||\n parseStandardValue(e.standardValue) === null ||\n typeof e.sourceKind !== 'string' ||\n !isValidSourceKind(e.sourceKind) ||\n typeof e.sourceRaw !== 'string' ||\n typeof e.sourceNumeric !== 'string' ||\n typeof e.targetKind !== 'string' ||\n !isValidSaveTargetKind(e.targetKind) ||\n typeof e.targetValue !== 'string' ||\n (e.targetUnit !== null && typeof e.targetUnit !== 'string') ||\n typeof e.note !== 'string'\n ) {\n return null\n }\n const tags = parseTagsField(e.tags)\n if (tags === null) return null\n return {\n id: e.id,\n savedAt: e.savedAt,\n standardValue: e.standardValue,\n sourceKind: e.sourceKind,\n sourceRaw: e.sourceRaw,\n sourceNumeric: e.sourceNumeric,\n targetKind: e.targetKind,\n targetValue: e.targetValue,\n targetUnit: e.targetUnit as string | null,\n note: e.note,\n tags,\n }\n}\n\nfunction compareBySavedAtDesc(a: HistoryEntry, b: HistoryEntry): number {\n return b.savedAt - a.savedAt\n}\n\nfunction compareByStandardValue(\n a: HistoryEntry,\n b: HistoryEntry,\n direction: 'asc' | 'desc',\n): number {\n const av = BigInt(a.standardValue)\n const bv = BigInt(b.standardValue)\n if (av < bv) return direction === 'asc' ? -1 : 1\n if (av > bv) return direction === 'asc' ? 1 : -1\n return compareBySavedAtDesc(a, b)\n}\n\nexport function sortHistoryEntries(\n entries: HistoryEntry[],\n mode: HistorySortMode,\n): HistoryEntry[] {\n const copy = [...entries]\n switch (mode) {\n case 'time-desc':\n return copy.sort((a, b) => b.savedAt - a.savedAt)\n case 'time-asc':\n return copy.sort((a, b) => a.savedAt - b.savedAt)\n case 'value-desc':\n return copy.sort((a, b) => compareByStandardValue(a, b, 'desc'))\n case 'value-asc':\n return copy.sort((a, b) => compareByStandardValue(a, b, 'asc'))\n }\n}\n\n/** History list source column: western numeric shows standardized digits; others show raw input. */\nexport function historySourceDisplay(e: HistoryEntry): string {\n if (\n (WESTERN_NUMERIC_SOURCE_KINDS as readonly SourceKind[]).includes(\n e.sourceKind,\n )\n ) {\n return e.sourceNumeric\n }\n return e.sourceRaw\n}\n\n/** History list target column card label. */\nexport function historyTargetKindLabel(kind: SaveTargetKind): string {\n if (isConversionTargetKind(kind)) {\n return CONVERSION_CARD_LABELS[kind]\n }\n return SOURCE_LABELS[kind]\n}\n\nconst CSV_HEADER = [\n '時間',\n '來源類型',\n '來源原始內容',\n '來源標準化數字',\n '儲存目標',\n '目標數值',\n '目標單位',\n '筆記',\n '標籤',\n] as const\n\nexport function historyToCsvRows(entries: HistoryEntry[]): string {\n const lines: string[][] = [CSV_HEADER as unknown as string[]]\n const sorted = sortHistoryEntries(entries, 'time-desc')\n for (const e of sorted) {\n const t = new Date(e.savedAt).toISOString()\n lines.push([\n t,\n e.sourceKind,\n e.sourceRaw,\n e.sourceNumeric,\n e.targetKind,\n e.targetValue,\n e.targetUnit ?? '',\n e.note,\n e.tags.join(';'),\n ])\n }\n return lines.map((row) => row.map(escapeCsvCell).join(',')).join('\\r\\n')\n}\n\nfunction escapeCsvCell(s: string): string {\n if (/[\",\\r\\n]/.test(s)) return `\"${s.replace(/\"/g, '\"\"')}\"`\n return s\n}\n\n/** UTF-8 with BOM for Excel */\nexport function csvBlobUtf8Bom(csv: string): Blob {\n const bom = new Uint8Array([0xef, 0xbb, 0xbf])\n return new Blob([bom, csv], { type: 'text/csv;charset=utf-8' })\n}\n\nexport function buildBackupPayload(entries: HistoryEntry[]): HistoryBackupFile {\n return {\n version: HISTORY_JSON_VERSION,\n exportedAt: new Date().toISOString(),\n entries,\n }\n}\n\nexport function stringifyBackup(payload: HistoryBackupFile): string {\n return `${JSON.stringify(payload, null, 2)}\\n`\n}\n\nexport type ImportHistoryResult =\n | { ok: true; entries: HistoryEntry[] }\n | { ok: false; message: string }\n\nexport function parseBackupJson(text: string): ImportHistoryResult {\n let data: unknown\n try {\n data = JSON.parse(text) as unknown\n } catch {\n return { ok: false, message: 'JSON 格式無法解析' }\n }\n if (!data || typeof data !== 'object') {\n return { ok: false, message: '備份檔內容不是物件' }\n }\n const rec = data as Record<string, unknown>\n if (\n !(SUPPORTED_HISTORY_JSON_VERSIONS as readonly number[]).includes(\n rec.version as number,\n )\n ) {\n return { ok: false, message: `不支援的版本:${String(rec.version)}` }\n }\n if (!Array.isArray(rec.entries)) {\n return { ok: false, message: '缺少 entries 陣列' }\n }\n const out: HistoryEntry[] = []\n for (const item of rec.entries) {\n const entry = parseHistoryEntry(item)\n if (!entry) {\n return { ok: false, message: '紀錄欄位不完整或型別不正確' }\n }\n out.push(entry)\n }\n return { ok: true, entries: out }\n}\n","import {\n type HistorySortMode,\n parseHistorySortMode,\n SUPPORTED_HISTORY_JSON_VERSIONS,\n} from './history'\nimport type { ConversionCardKind, SourceKind } from './types'\nimport { CONVERSION_CARD_KINDS, SOURCE_KINDS } from './types'\n\nexport const APP_SETTINGS_JSON_VERSION = 1 as const\nexport const APP_SETTINGS_KIND = 'scale-sense-app-settings' as const\n\nexport type AppSettingsSnapshot = {\n sourceKind: SourceKind\n rawInput: string\n cardHidden: Record<SourceKind, boolean>\n conversionCardHidden: Record<ConversionCardKind, boolean>\n historySortMode: HistorySortMode\n savedCustomUnits: string[]\n}\n\nexport type AppSettingsBackupFile = {\n kind: typeof APP_SETTINGS_KIND\n version: typeof APP_SETTINGS_JSON_VERSION\n exportedAt: string\n settings: AppSettingsSnapshot\n}\n\nfunction isValidSourceKind(k: string): k is SourceKind {\n return (SOURCE_KINDS as readonly string[]).includes(k)\n}\n\nfunction parseCardHidden(value: unknown): Record<SourceKind, boolean> | null {\n if (!value || typeof value !== 'object') return null\n const rec = value as Record<string, unknown>\n const out = {} as Record<SourceKind, boolean>\n for (const kind of SOURCE_KINDS) {\n if (typeof rec[kind] !== 'boolean') return null\n out[kind] = rec[kind]\n }\n return out\n}\n\nfunction parseConversionCardHidden(\n value: unknown,\n): Record<ConversionCardKind, boolean> | null {\n if (!value || typeof value !== 'object') return null\n const rec = value as Record<string, unknown>\n const out = {} as Record<ConversionCardKind, boolean>\n for (const kind of CONVERSION_CARD_KINDS) {\n if (typeof rec[kind] !== 'boolean') return null\n out[kind] = rec[kind]\n }\n return out\n}\n\nfunction parseSavedCustomUnits(value: unknown): string[] | null {\n if (!Array.isArray(value)) return null\n if (!value.every((u) => typeof u === 'string')) return null\n return value\n}\n\nexport function parseAppSettingsSnapshot(\n value: unknown,\n): AppSettingsSnapshot | null {\n if (!value || typeof value !== 'object') return null\n const rec = value as Record<string, unknown>\n\n if (\n typeof rec.sourceKind !== 'string' ||\n !isValidSourceKind(rec.sourceKind)\n ) {\n return null\n }\n if (typeof rec.rawInput !== 'string') return null\n\n const cardHidden = parseCardHidden(rec.cardHidden)\n if (!cardHidden) return null\n\n const conversionCardHidden = parseConversionCardHidden(\n rec.conversionCardHidden,\n )\n if (!conversionCardHidden) return null\n\n const savedCustomUnits = parseSavedCustomUnits(rec.savedCustomUnits)\n if (!savedCustomUnits) return null\n\n return {\n sourceKind: rec.sourceKind,\n rawInput: rec.rawInput,\n cardHidden,\n conversionCardHidden,\n historySortMode: parseHistorySortMode(rec.historySortMode),\n savedCustomUnits,\n }\n}\n\nexport function buildAppSettingsPayload(\n settings: AppSettingsSnapshot,\n): AppSettingsBackupFile {\n return {\n kind: APP_SETTINGS_KIND,\n version: APP_SETTINGS_JSON_VERSION,\n exportedAt: new Date().toISOString(),\n settings,\n }\n}\n\nexport function stringifyAppSettingsBackup(\n payload: AppSettingsBackupFile,\n): string {\n return `${JSON.stringify(payload, null, 2)}\\n`\n}\n\nexport type ImportAppSettingsResult =\n | { ok: true; settings: AppSettingsSnapshot }\n | { ok: false; message: string }\n\nexport function parseAppSettingsBackup(text: string): ImportAppSettingsResult {\n let data: unknown\n try {\n data = JSON.parse(text) as unknown\n } catch {\n return { ok: false, message: 'JSON 格式無法解析' }\n }\n if (!data || typeof data !== 'object') {\n return { ok: false, message: '備份檔內容不是物件' }\n }\n const rec = data as Record<string, unknown>\n\n if (\n rec.kind !== APP_SETTINGS_KIND &&\n (SUPPORTED_HISTORY_JSON_VERSIONS as readonly number[]).includes(\n rec.version as number,\n ) &&\n Array.isArray(rec.entries)\n ) {\n return {\n ok: false,\n message: '此檔為歷史備份,請至收藏頁匯入',\n }\n }\n\n if (rec.kind !== APP_SETTINGS_KIND) {\n return { ok: false, message: '不是有效的設定備份檔' }\n }\n if (rec.version !== APP_SETTINGS_JSON_VERSION) {\n return { ok: false, message: `不支援的版本:${String(rec.version)}` }\n }\n\n const settings = parseAppSettingsSnapshot(rec.settings)\n if (!settings) {\n return { ok: false, message: '設定欄位不完整或型別不正確' }\n }\n return { ok: true, settings }\n}\n","import type { ConversionCardKind, SourceKind } from './types'\n\nconst DIGITS_CN = [\n '零',\n '一',\n '二',\n '三',\n '四',\n '五',\n '六',\n '七',\n '八',\n '九',\n] as const\n\nexport function formatWesternNumericValue(n: bigint): string {\n if (n === 0n) return '0'\n const neg = n < 0n\n const v = neg ? -n : n\n const s = v.toString()\n const parts: string[] = []\n for (let i = s.length; i > 0; i -= 3) {\n const start = Math.max(0, i - 3)\n parts.push(s.slice(start, i))\n }\n const out = parts.reverse().join(',')\n return neg ? `-${out}` : out\n}\n\nconst NAMES_UNDER_20 = [\n 'zero',\n 'one',\n 'two',\n 'three',\n 'four',\n 'five',\n 'six',\n 'seven',\n 'eight',\n 'nine',\n 'ten',\n 'eleven',\n 'twelve',\n 'thirteen',\n 'fourteen',\n 'fifteen',\n 'sixteen',\n 'seventeen',\n 'eighteen',\n 'nineteen',\n] as const\n\nconst TENS = [\n '',\n '',\n 'twenty',\n 'thirty',\n 'forty',\n 'fifty',\n 'sixty',\n 'seventy',\n 'eighty',\n 'ninety',\n] as const\n\nfunction underThousandEnglish(n: number): string {\n if (n === 0) return ''\n if (n < 20) return NAMES_UNDER_20[n]\n if (n < 100) {\n const t = Math.floor(n / 10)\n const o = n % 10\n return o ? `${TENS[t]}-${underThousandEnglish(o)}` : TENS[t]\n }\n const h = Math.floor(n / 100)\n const rest = n % 100\n const head = `${NAMES_UNDER_20[h]} hundred`\n return rest ? `${head} ${underThousandEnglish(rest)}` : head\n}\n\nexport function formatWesternWordsValue(n: bigint): string {\n if (n === 0n) return 'zero'\n const neg = n < 0n\n let v = neg ? -n : n\n if (v > 1_000_000_000_000_000n) {\n return `${formatWesternNumericValue(n)} (超出可轉換為英文語意的範圍)`\n }\n\n const scales = [\n { name: 'trillion', value: 1_000_000_000_000n },\n { name: 'billion', value: 1_000_000_000n },\n { name: 'million', value: 1_000_000n },\n { name: 'thousand', value: 1000n },\n ] as const\n\n const parts: string[] = []\n for (const { name, value } of scales) {\n if (v >= value) {\n const c = Number(v / value)\n v %= value\n parts.push(`${underThousandEnglish(c)} ${name}`.trim())\n }\n }\n if (v > 0n) {\n parts.push(underThousandEnglish(Number(v)))\n }\n const core = parts.join(' ').replace(/\\s+/g, ' ').trim()\n return neg ? `negative ${core}` : core\n}\n\nfunction fourDigitToCn(n: number): string {\n if (n === 0) return ''\n const q = Math.floor(n / 1000)\n const b = Math.floor((n % 1000) / 100)\n const s = Math.floor((n % 100) / 10)\n const o = n % 10\n let out = ''\n if (q > 0) out += `${DIGITS_CN[q]}千`\n if (b > 0) out += `${DIGITS_CN[b]}百`\n else if (q > 0 && (s > 0 || o > 0)) out += '零'\n if (s > 0) out += `${DIGITS_CN[s]}十`\n else if (b > 0 && o > 0) out += '零'\n if (o > 0) out += DIGITS_CN[o]\n return out\n}\n\nexport function formatChineseGroupedValue(n: bigint): string {\n if (n === 0n) return '0'\n const neg = n < 0n\n let v = neg ? -n : n\n const groups: number[] = []\n while (v > 0n) {\n const g = Number(v % 10000n)\n groups.push(g)\n v /= 10000n\n }\n const normalizedGroups = groups\n .reverse()\n .map((group, idx) =>\n idx === 0 ? String(group) : String(group).padStart(4, '0'),\n )\n const body = normalizedGroups.join(',')\n return neg ? `-${body}` : body\n}\n\nexport function formatChineseWordsValue(n: bigint): string {\n if (n === 0n) return '零'\n const neg = n < 0n\n let v = neg ? -n : n\n if (v >= 1_000_000_000_000_000n) {\n return `${formatWesternNumericValue(n)}(數值過大,中文語意顯示為簡化形式)`\n }\n\n const 兆 = 1_000_000_000_000n\n const 億 = 100_000_000n\n const 萬 = 10_000n\n\n const parts: string[] = []\n const zhao = v / 兆\n if (zhao > 0n) {\n parts.push(`${fourDigitToCn(Number(zhao))}兆`.replace(/^一十/, '十'))\n v %= 兆\n }\n const yi = v / 億\n if (yi > 0n) {\n parts.push(`${fourDigitToCn(Number(yi))}億`.replace(/^一十/, '十'))\n v %= 億\n }\n const wan = v / 萬\n if (wan > 0n) {\n parts.push(`${fourDigitToCn(Number(wan))}萬`.replace(/^一十/, '十'))\n v %= 萬\n }\n if (v > 0n) {\n parts.push(fourDigitToCn(Number(v)))\n }\n const core = parts.join('').replace(/零+/g, '零').replace(/零$/, '')\n const out = core || '零'\n return neg ? `負${out}` : out\n}\n\nexport function formatDigitalWordsValue(n: bigint): string {\n return formatWesternNumericValue(n)\n}\n\nexport function formatValueAsKind(n: bigint, kind: SourceKind): string {\n switch (kind) {\n case 'westernNumeric':\n return formatWesternNumericValue(n)\n case 'westernWords':\n return formatWesternWordsValue(n)\n case 'chineseGrouped':\n return formatChineseGroupedValue(n)\n case 'chineseWords':\n return formatChineseWordsValue(n)\n case 'digitalWords':\n return formatDigitalWordsValue(n)\n default:\n return ''\n }\n}\n\nconst USD_RATE_DEN = 32n\n\nfunction formatDecimalRatio(\n numerator: bigint,\n denominator: bigint,\n maxFractionDigits = 6,\n): string {\n const intPart = numerator / denominator\n let remainder = numerator % denominator\n const intText = formatWesternNumericValue(intPart)\n if (remainder === 0n) return intText\n\n let fraction = ''\n for (let i = 0; i < maxFractionDigits && remainder !== 0n; i++) {\n remainder *= 10n\n fraction += (remainder / denominator).toString()\n remainder %= denominator\n }\n fraction = fraction.replace(/0+$/, '')\n return fraction ? `${intText}.${fraction}` : intText\n}\n\nexport type ConversionCardView = {\n source: string\n target: string\n}\n\n/** Extract the numeric portion from a conversion card target string (e.g. `96 byte`). */\nexport function conversionTargetNumeric(target: string): string {\n const m = target.match(/^(.+)\\s+[A-Za-z]+$/)\n return m ? m[1] : target\n}\n\nexport function formatConversionCard(\n value: bigint,\n kind: ConversionCardKind,\n): ConversionCardView {\n switch (kind) {\n case 'bitToByte':\n return {\n source: `${formatWesternNumericValue(value)} bit`,\n target: `${formatDecimalRatio(value, 8n)} byte`,\n }\n case 'byteToBit':\n return {\n source: `${formatWesternNumericValue(value)} byte`,\n target: `${formatWesternNumericValue(value * 8n)} bit`,\n }\n case 'twdToUsd':\n return {\n source: `${formatWesternNumericValue(value)} TWD`,\n target: `${formatDecimalRatio(value, USD_RATE_DEN)} USD`,\n }\n case 'usdToTwd':\n return {\n source: `${formatWesternNumericValue(value)} USD`,\n target: `${formatWesternNumericValue(value * USD_RATE_DEN)} TWD`,\n }\n default:\n return { source: '-', target: '-' }\n }\n}\n","import { formatWesternNumericValue } from './format'\nimport type { HistoryEntry } from './history'\nimport { parseStandardValue } from './history'\n\nexport type ChartKind = 'bar' | 'barHorizontal' | 'scatter'\n\nexport const CHART_KIND_LABELS: Record<ChartKind, string> = {\n bar: '長條圖',\n barHorizontal: '橫向長條圖',\n scatter: '散點圖',\n}\n\nexport type ChartPoint = {\n id: string\n order: number\n value: number | null\n valueLabel: string\n shortLabel: string\n entry: HistoryEntry\n}\n\nexport function truncateNoteLabel(note: string, order: number): string {\n const trimmed = note.trim()\n if (trimmed.length === 0) return `#${order}`\n return [...trimmed].slice(0, 2).join('')\n}\n\nexport function toChartNumeric(standardValue: string): number | null {\n const parsed = parseStandardValue(standardValue)\n if (parsed === null) return null\n if (parsed <= 0n) return null\n const n = Number(parsed)\n if (!Number.isFinite(n) || n <= 0) return null\n return n\n}\n\nexport function buildChartPoints(entries: HistoryEntry[]): ChartPoint[] {\n return entries.map((entry, index) => {\n const order = index + 1\n const parsed = parseStandardValue(entry.standardValue)\n const valueLabel =\n parsed !== null ? formatWesternNumericValue(parsed) : entry.standardValue\n return {\n id: entry.id,\n order,\n value: toChartNumeric(entry.standardValue),\n valueLabel,\n shortLabel: truncateNoteLabel(entry.note, order),\n entry,\n }\n })\n}\n\nexport function canUseLogScale(points: ChartPoint[]): boolean {\n if (points.length === 0) return false\n return points.every((p) => p.value !== null && p.value > 0)\n}\n\n/** Recharts log axes default to a domain that includes 0 and breaks rendering; set an explicit positive lower bound. */\nexport function computeLogValueDomain(points: ChartPoint[]): [number, 'auto'] {\n const values = points\n .map((p) => p.value)\n .filter((v): v is number => v !== null && v > 0)\n if (values.length === 0) return [1, 'auto']\n const min = Math.min(...values)\n return [min * 0.5, 'auto']\n}\n\nconst HORIZONTAL_BAR_ROW_HEIGHT = 36\nconst HORIZONTAL_BAR_CHART_PADDING = 40\nconst MIN_CHART_HEIGHT = 192\n\nexport function horizontalBarChartHeight(pointCount: number): number {\n if (pointCount <= 0) return MIN_CHART_HEIGHT\n return Math.max(\n MIN_CHART_HEIGHT,\n pointCount * HORIZONTAL_BAR_ROW_HEIGHT + HORIZONTAL_BAR_CHART_PADDING,\n )\n}\n","/** Internal classification for numeric + unit semantics (kilo … peta). */\nexport type DigitalByteUnit = 'k' | 'm' | 'g' | 't' | 'p'\n\n/** SI (decimal): 10³ per level. */\nexport const DECIMAL_KB = 1_000n\nexport const DECIMAL_MB = 1_000_000n\nexport const DECIMAL_GB = 1_000_000_000n\nexport const DECIMAL_TB = 1_000_000_000_000n\nexport const DECIMAL_PB = 1_000_000_000_000_000n\n\nconst DECIMAL_BY_UNIT: Record<DigitalByteUnit, bigint> = {\n k: DECIMAL_KB,\n m: DECIMAL_MB,\n g: DECIMAL_GB,\n t: DECIMAL_TB,\n p: DECIMAL_PB,\n}\nexport function digitalUnitToScalar(unit: DigitalByteUnit): bigint {\n return DECIMAL_BY_UNIT[unit]\n}\n","import { type DigitalByteUnit, digitalUnitToScalar } from './digital'\nimport type { ParseOutcome, SourceKind } from './types'\n\nconst WS = /\\s+/\n\nconst UNITS_EN: Record<string, bigint> = {\n thousand: 1000n,\n million: 1_000_000n,\n billion: 1_000_000_000n,\n trillion: 1_000_000_000_000n,\n}\n\nconst UNIT_PREFIXES = ['thousand', 'million', 'billion', 'trillion'] as const\n\nfunction isIncompleteEnglishUnitToken(s: string): boolean {\n const t = s.toLowerCase()\n if (UNITS_EN[t] !== undefined) return false\n return UNIT_PREFIXES.some((u) => u.startsWith(t) && t.length > 0)\n}\n\nfunction parseDigitToken(raw: string): bigint | null {\n const cleaned = raw.replace(/,/g, '')\n if (!/^\\d+$/.test(cleaned)) return null\n return BigInt(cleaned)\n}\n\nexport function parseWesternNumeric(raw: string): ParseOutcome {\n const s = raw.trim()\n if (s.length === 0) return { kind: 'error', message: '請輸入數字' }\n const cleaned = s.replace(/,/g, '').replace(/\\s+/g, '')\n if (!/^\\d+$/.test(cleaned)) {\n if (/^\\d*$/.test(cleaned) && cleaned.length > 0)\n return { kind: 'incomplete' }\n return { kind: 'error', message: '僅支援整數與千分位逗號' }\n }\n return { kind: 'ok', value: BigInt(cleaned) }\n}\n\nexport function parseWesternWords(raw: string): ParseOutcome {\n const s = raw.trim().toLowerCase()\n if (s.length === 0) return { kind: 'error', message: '請輸入英文數字語意' }\n\n const tokens = s.split(WS).filter(Boolean)\n if (tokens.length === 0)\n return { kind: 'error', message: '請輸入英文數字語意' }\n\n if (tokens.length === 1 && UNITS_EN[tokens[0]] !== undefined) {\n return { kind: 'error', message: '單位前需有數字' }\n }\n\n let sum = 0n\n let current = 0n\n let expectingNumber = true\n\n for (const tok of tokens) {\n const mult = UNITS_EN[tok]\n if (mult !== undefined) {\n if (expectingNumber && tokens.indexOf(tok) === 0) {\n return { kind: 'error', message: '單位前需有數字' }\n }\n sum += current * mult\n current = 0n\n expectingNumber = true\n continue\n }\n\n const n = parseDigitToken(tok)\n if (n !== null) {\n current = n\n expectingNumber = false\n continue\n }\n\n if (isIncompleteEnglishUnitToken(tok)) return { kind: 'incomplete' }\n return { kind: 'error', message: '無法辨識的英文單位或數字' }\n }\n\n if (expectingNumber && tokens.length > 0) {\n const last = tokens[tokens.length - 1]\n if (isIncompleteEnglishUnitToken(last)) return { kind: 'incomplete' }\n }\n\n sum += current\n return { kind: 'ok', value: sum }\n}\n\nexport function parseChineseGrouped(raw: string): ParseOutcome {\n const s = raw.trim()\n if (s.length === 0) return { kind: 'error', message: '請輸入中文分節數字' }\n\n const parts = s.split(',').map((p) => p.trim())\n if (parts.some((p) => p.length === 0)) return { kind: 'incomplete' }\n\n for (const p of parts) {\n if (!/^\\d{1,4}$/.test(p)) {\n if (/^\\d*$/.test(p) && p.length > 0 && p.length <= 4)\n return { kind: 'incomplete' }\n return { kind: 'error', message: '每段需為 1–4 位數字' }\n }\n }\n\n const n = parts.length\n let total = 0n\n for (let i = 0; i < n; i++) {\n const g = BigInt(parts[i])\n const exp = BigInt(n - 1 - i) * 4n\n total += g * 10n ** exp\n }\n return { kind: 'ok', value: total }\n}\n\nconst CN_UNITS: Record<string, bigint> = {\n 萬: 10_000n,\n 億: 100_000_000n,\n 兆: 1_000_000_000_000n,\n}\n\nconst CN_UNIT_ORDER: Record<keyof typeof CN_UNITS, number> = {\n 兆: 3,\n 億: 2,\n 萬: 1,\n}\n\nfunction pow10(exp: number): bigint {\n return 10n ** BigInt(exp)\n}\n\nfunction parseChineseCoeff(\n token: string,\n unit: keyof typeof CN_UNITS | null,\n): ParseOutcome {\n if (!/^\\d+(?:\\.\\d+)?$/.test(token)) {\n return { kind: 'error', message: '中文語意係數格式不正確' }\n }\n\n if (!token.includes('.')) {\n const base = BigInt(token)\n return { kind: 'ok', value: unit ? base * CN_UNITS[unit] : base }\n }\n\n if (!unit) {\n return { kind: 'error', message: '小數需搭配萬/億/兆單位' }\n }\n\n const [intPart, fracPart] = token.split('.')\n if (!fracPart || fracPart.length === 0) return { kind: 'incomplete' }\n if (fracPart.length > 4) {\n return { kind: 'error', message: '小數位數最多 4 位' }\n }\n\n const scaled = BigInt(`${intPart}${fracPart}`)\n const scale = pow10(fracPart.length)\n const numer = scaled * CN_UNITS[unit]\n if (numer % scale !== 0n) {\n return { kind: 'error', message: '小數無法精確換算為整數' }\n }\n\n return { kind: 'ok', value: numer / scale }\n}\n\nexport function parseChineseWords(raw: string): ParseOutcome {\n const s = raw.trim().replace(/\\s+/g, '')\n if (s.length === 0) return { kind: 'error', message: '請輸入中文語意數字' }\n if (!/^[\\d.萬億兆]+$/.test(s)) {\n return { kind: 'error', message: '僅支援數字、小數點與萬/億/兆' }\n }\n if (/^\\d+\\.\\d{0,4}$/.test(s)) return { kind: 'incomplete' }\n\n let total = 0n\n let cursor = 0\n let lastOrder = Number.POSITIVE_INFINITY\n let seenUnit = false\n let hasTail = false\n\n while (cursor < s.length) {\n const tokenMatch = s.slice(cursor).match(/^(\\d+(?:\\.\\d+)?)/)\n if (!tokenMatch) {\n return { kind: 'error', message: '中文語意格式不正確' }\n }\n\n const coeff = tokenMatch[1]\n cursor += coeff.length\n const next = s[cursor] ?? ''\n const hasUnit = next === '兆' || next === '億' || next === '萬'\n\n if (hasTail && (hasUnit || coeff.length > 0)) {\n return { kind: 'error', message: '尾段數字後不可再接新片段' }\n }\n\n if (hasUnit) {\n const unit = next as keyof typeof CN_UNITS\n const order = CN_UNIT_ORDER[unit]\n if (order >= lastOrder) {\n return { kind: 'error', message: '中文單位需由大到小且不可重複' }\n }\n\n const parsed = parseChineseCoeff(coeff, unit)\n if (parsed.kind !== 'ok') return parsed\n total += parsed.value\n seenUnit = true\n lastOrder = order\n cursor += 1\n continue\n }\n\n if (coeff.includes('.')) {\n return { kind: 'error', message: '小數需搭配萬/億/兆單位' }\n }\n const parsedTail = parseChineseCoeff(coeff, null)\n if (parsedTail.kind !== 'ok') return parsedTail\n total += parsedTail.value\n hasTail = seenUnit\n if (cursor < s.length) {\n return { kind: 'error', message: '中文語意格式不正確' }\n }\n }\n\n return { kind: 'ok', value: total }\n}\n\nconst DIG_WORDS: Record<string, DigitalByteUnit> = {\n kilo: 'k',\n kilobyte: 'k',\n kilobytes: 'k',\n k: 'k',\n mega: 'm',\n megabyte: 'm',\n megabytes: 'm',\n m: 'm',\n giga: 'g',\n gigabyte: 'g',\n gigabytes: 'g',\n g: 'g',\n tera: 't',\n terabyte: 't',\n terabytes: 't',\n t: 't',\n peta: 'p',\n petabyte: 'p',\n petabytes: 'p',\n p: 'p',\n}\n\nexport function parseDigitalWords(raw: string): ParseOutcome {\n const s = raw.trim().toLowerCase()\n if (s.length === 0)\n return { kind: 'error', message: '請輸入 Digital 語意(如 1 giga 或 1 G)' }\n\n const m = s.match(/^([\\d,]+)\\s*([a-z]+)\\s*$/)\n if (!m) {\n if (/^[\\d,]*$/.test(s)) return { kind: 'incomplete' }\n return {\n kind: 'error',\n message: '格式應為「數字 + 單位(如 kilo、G)」',\n }\n }\n\n const num = parseDigitToken(m[1])\n if (num === null) return { kind: 'error', message: '數字格式不正確' }\n\n const unitKey = m[2]\n const kind = DIG_WORDS[unitKey]\n if (!kind) {\n const partial = Object.keys(DIG_WORDS).some(\n (k) => k.startsWith(unitKey) && unitKey.length > 0,\n )\n if (partial) return { kind: 'incomplete' }\n return {\n kind: 'error',\n message: '僅支援 kilo/mega/giga/tera/peta(或 K/M/G/T/P)',\n }\n }\n\n const mult = digitalUnitToScalar(kind)\n return { kind: 'ok', value: num * mult }\n}\n\nexport function parseByKind(kind: SourceKind, raw: string): ParseOutcome {\n const trimmed = raw.trim()\n if (trimmed.length === 0) return { kind: 'error', message: '請輸入內容' }\n\n switch (kind) {\n case 'westernNumeric':\n return parseWesternNumeric(raw)\n case 'westernWords':\n return parseWesternWords(raw)\n case 'chineseGrouped':\n return parseChineseGrouped(raw)\n case 'chineseWords':\n return parseChineseWords(raw)\n case 'digitalWords':\n return parseDigitalWords(raw)\n default:\n return { kind: 'error', message: '未知欄位' }\n }\n}\n","import { formatValueAsKind } from './format'\nimport { parseByKind } from './parse'\nimport type { PipelineStatus, SourceKind } from './types'\nimport { SOURCE_KINDS } from './types'\n\nexport type PipelineResult = {\n status: PipelineStatus\n /** User-facing message when status is error */\n errorMessage?: string\n standardValue: bigint | null\n /** Formatted value per card; use '--' when not shown in UI layer */\n formattedByKind: Record<SourceKind, string>\n}\n\nexport function runPipeline(\n sourceKind: SourceKind,\n rawInput: string,\n): PipelineResult {\n const empty = makeEmptyOutputs()\n const trimmed = rawInput.trim()\n if (trimmed.length === 0) {\n return { status: 'empty', standardValue: null, formattedByKind: empty }\n }\n\n const outcome = parseByKind(sourceKind, rawInput)\n if (outcome.kind === 'incomplete') {\n return { status: 'incomplete', standardValue: null, formattedByKind: empty }\n }\n if (outcome.kind === 'error') {\n return {\n status: 'error',\n errorMessage: outcome.message,\n standardValue: null,\n formattedByKind: empty,\n }\n }\n\n const v = outcome.value\n const formattedByKind = {} as Record<SourceKind, string>\n for (const k of SOURCE_KINDS) {\n formattedByKind[k] = formatValueAsKind(v, k)\n }\n return { status: 'ok', standardValue: v, formattedByKind }\n}\n\nfunction makeEmptyOutputs(): Record<SourceKind, string> {\n const o = {} as Record<SourceKind, string>\n for (const k of SOURCE_KINDS) o[k] = ''\n return o\n}\n","import { SAVE_UNIT_PRESETS } from './types'\n\nexport function normalizeUnitLabel(unit: string): string {\n return unit.trim()\n}\n\nexport function isBuiltInUnit(unit: string): boolean {\n return (SAVE_UNIT_PRESETS as readonly string[]).includes(unit)\n}\n\nexport function shouldRememberCustomUnit(\n unit: string,\n savedCustomUnits: readonly string[],\n): boolean {\n const normalized = normalizeUnitLabel(unit)\n if (normalized.length === 0) return false\n if (isBuiltInUnit(normalized)) return false\n if (savedCustomUnits.includes(normalized)) return false\n return true\n}\n"],"mappings":"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","names":["isValidSourceKind"]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@scale-sense/core",
3
+ "version": "0.1.0",
4
+ "description": "Framework-agnostic numeric conversion engine for ScaleSense",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/scale-sense/scale-sense-sdk.git",
12
+ "directory": "packages/core"
13
+ },
14
+ "type": "module",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "main": "./dist/index.js",
19
+ "module": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "lint": "biome check .",
30
+ "test": "bun test src"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.5.0",
34
+ "typescript": "~5.9.3"
35
+ }
36
+ }