@sayue_ltr/fleq 1.50.0 → 1.51.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.
- package/CHANGELOG.md +103 -0
- package/README.md +47 -5
- package/dist/config.js +35 -2
- package/dist/dmdata/rest-client.js +58 -3
- package/dist/dmdata/telegram-parser.js +37 -59
- package/dist/dmdata/ws-client.js +49 -18
- package/dist/engine/cli/cli-run.js +71 -1
- package/dist/engine/cli/cli.js +12 -0
- package/dist/engine/filter/compile-filter.js +21 -0
- package/dist/engine/filter/compiler.js +188 -0
- package/dist/engine/filter/errors.js +41 -0
- package/dist/engine/filter/field-registry.js +78 -0
- package/dist/engine/filter/index.js +15 -0
- package/dist/engine/filter/parser.js +137 -0
- package/dist/engine/filter/rank-maps.js +34 -0
- package/dist/engine/filter/tokenizer.js +121 -0
- package/dist/engine/filter/type-checker.js +104 -0
- package/dist/engine/filter/types.js +2 -0
- package/dist/engine/filter-template/pipeline-controller.js +73 -0
- package/dist/engine/filter-template/pipeline.js +16 -0
- package/dist/engine/messages/display-callbacks.js +7 -0
- package/dist/engine/messages/message-router.js +114 -182
- package/dist/engine/messages/summary-tracker.js +106 -0
- package/dist/engine/messages/telegram-stats.js +103 -0
- package/dist/engine/messages/volcano-route-handler.js +122 -0
- package/dist/engine/monitor/monitor.js +51 -3
- package/dist/engine/monitor/shutdown.js +1 -0
- package/dist/engine/notification/notifier.js +16 -1
- package/dist/engine/notification/sound-player.js +193 -28
- package/dist/engine/presentation/diff-store.js +158 -0
- package/dist/engine/presentation/diff-types.js +2 -0
- package/dist/engine/presentation/events/from-earthquake.js +53 -0
- package/dist/engine/presentation/events/from-eew.js +72 -0
- package/dist/engine/presentation/events/from-lg-observation.js +58 -0
- package/dist/engine/presentation/events/from-nankai-trough.js +39 -0
- package/dist/engine/presentation/events/from-raw.js +35 -0
- package/dist/engine/presentation/events/from-seismic-text.js +37 -0
- package/dist/engine/presentation/events/from-tsunami.js +51 -0
- package/dist/engine/presentation/events/from-volcano.js +88 -0
- package/dist/engine/presentation/events/to-presentation-event.js +32 -0
- package/dist/engine/presentation/level-helpers.js +118 -0
- package/dist/engine/presentation/processors/process-earthquake.js +36 -0
- package/dist/engine/presentation/processors/process-eew.js +90 -0
- package/dist/engine/presentation/processors/process-lg-observation.js +30 -0
- package/dist/engine/presentation/processors/process-message.js +53 -0
- package/dist/engine/presentation/processors/process-nankai-trough.js +30 -0
- package/dist/engine/presentation/processors/process-raw.js +22 -0
- package/dist/engine/presentation/processors/process-seismic-text.js +30 -0
- package/dist/engine/presentation/processors/process-tsunami.js +42 -0
- package/dist/engine/presentation/processors/process-volcano.js +41 -0
- package/dist/engine/presentation/types.js +2 -0
- package/dist/engine/startup/config-resolver.js +2 -0
- package/dist/engine/template/compile-template.js +18 -0
- package/dist/engine/template/compiler.js +102 -0
- package/dist/engine/template/field-accessor.js +25 -0
- package/dist/engine/template/filters.js +94 -0
- package/dist/engine/template/index.js +5 -0
- package/dist/engine/template/parser.js +190 -0
- package/dist/engine/template/tokenizer.js +96 -0
- package/dist/engine/template/types.js +2 -0
- package/dist/types.js +2 -1
- package/dist/ui/display-adapter.js +60 -0
- package/dist/ui/earthquake-formatter.js +17 -5
- package/dist/ui/eew-formatter.js +25 -10
- package/dist/ui/formatter.js +67 -32
- package/dist/ui/minimap/grid-layout.js +91 -0
- package/dist/ui/minimap/index.js +16 -0
- package/dist/ui/minimap/minimap-renderer.js +277 -0
- package/dist/ui/minimap/pref-mapping.js +82 -0
- package/dist/ui/minimap/types.js +2 -0
- package/dist/ui/night-overlay.js +56 -0
- package/dist/ui/repl-handlers/command-definitions.js +320 -0
- package/dist/ui/repl-handlers/index.js +11 -0
- package/dist/ui/repl-handlers/info-handlers.js +577 -0
- package/dist/ui/repl-handlers/operation-handlers.js +233 -0
- package/dist/ui/repl-handlers/settings-handlers.js +923 -0
- package/dist/ui/repl-handlers/types.js +10 -0
- package/dist/ui/repl.js +81 -1752
- package/dist/ui/statistics-formatter.js +208 -0
- package/dist/ui/status-line.js +69 -0
- package/dist/ui/summary/index.js +5 -0
- package/dist/ui/summary/summary-line.js +18 -0
- package/dist/ui/summary/summary-model.js +31 -0
- package/dist/ui/summary/token-builders.js +317 -0
- package/dist/ui/summary/types.js +2 -0
- package/dist/ui/summary/width-fit.js +41 -0
- package/dist/ui/summary-interval-formatter.js +72 -0
- package/dist/ui/theme.js +34 -5
- package/dist/ui/tip-shuffler.js +81 -0
- package/dist/ui/volcano-formatter.js +15 -13
- package/dist/ui/waiting-tips.js +289 -249
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALL_PREF_IDS = exports.PREF_PLACEMENTS = exports.GRID_COLS = exports.GRID_ROWS = void 0;
|
|
4
|
+
exports.GRID_ROWS = 12;
|
|
5
|
+
exports.GRID_COLS = 13;
|
|
6
|
+
/** Helper to create a placement */
|
|
7
|
+
function p(id, cells, anchor) {
|
|
8
|
+
return {
|
|
9
|
+
id,
|
|
10
|
+
cells: cells.map(([row, col]) => ({ row, col })),
|
|
11
|
+
anchor: { row: anchor[0], col: anchor[1] },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* All 47 prefecture placements on the 12×13 grid.
|
|
16
|
+
*
|
|
17
|
+
* Grid layout (from spec):
|
|
18
|
+
* Col: 0 1 2 3 4 5 6 7 8 9 10 11 12
|
|
19
|
+
* r00: HK *HK HK HK
|
|
20
|
+
* r01: HK HK HK HK *AO AO
|
|
21
|
+
* r02: AK IT
|
|
22
|
+
* r03: YG MG
|
|
23
|
+
* r04: OK *FS FS
|
|
24
|
+
* r05: *IS *NI NI TC IB
|
|
25
|
+
* r06: TM IS *NA GI GU ST
|
|
26
|
+
* r07: SM TT *HG KY *FI FI NA YN TY *CB
|
|
27
|
+
* r08: YA HS OY HG SI *ME AI SZ KN CB
|
|
28
|
+
* r09: NS SG FO OS NR ME
|
|
29
|
+
* r10: KU OI EH KA WA
|
|
30
|
+
* r11: KG MZ *KO KO TK
|
|
31
|
+
*/
|
|
32
|
+
exports.PREF_PLACEMENTS = [
|
|
33
|
+
// ── 北海道 (4×2) ──
|
|
34
|
+
p("HK", [[0, 3], [0, 4], [0, 5], [0, 6], [1, 3], [1, 4], [1, 5], [1, 6]], [0, 4]),
|
|
35
|
+
// ── 東北 ──
|
|
36
|
+
p("AO", [[1, 11], [1, 12]], [1, 11]),
|
|
37
|
+
p("AK", [[2, 11]], [2, 11]),
|
|
38
|
+
p("IT", [[2, 12]], [2, 12]),
|
|
39
|
+
p("YG", [[3, 11]], [3, 11]),
|
|
40
|
+
p("MG", [[3, 12]], [3, 12]),
|
|
41
|
+
p("FS", [[4, 11], [4, 12]], [4, 11]),
|
|
42
|
+
// ── 関東 ──
|
|
43
|
+
p("IB", [[5, 12]], [5, 12]),
|
|
44
|
+
p("TC", [[5, 11]], [5, 11]),
|
|
45
|
+
p("GU", [[6, 11]], [6, 11]),
|
|
46
|
+
p("ST", [[6, 12]], [6, 12]),
|
|
47
|
+
p("CB", [[7, 12], [8, 12]], [7, 12]),
|
|
48
|
+
p("TY", [[7, 11]], [7, 11]),
|
|
49
|
+
p("KN", [[8, 11]], [8, 11]),
|
|
50
|
+
// ── 中部 ──
|
|
51
|
+
p("NI", [[5, 9], [5, 10]], [5, 9]),
|
|
52
|
+
p("TM", [[6, 7]], [6, 7]),
|
|
53
|
+
p("IS", [[5, 8], [6, 8]], [5, 8]),
|
|
54
|
+
p("FI", [[7, 7], [7, 8]], [7, 7]),
|
|
55
|
+
p("YN", [[7, 10]], [7, 10]),
|
|
56
|
+
p("NA", [[6, 9], [7, 9]], [6, 9]),
|
|
57
|
+
p("GI", [[6, 10]], [6, 10]),
|
|
58
|
+
p("SZ", [[8, 10]], [8, 10]),
|
|
59
|
+
p("AI", [[8, 9]], [8, 9]),
|
|
60
|
+
// ── 近畿 ──
|
|
61
|
+
p("ME", [[8, 8], [9, 8]], [8, 8]),
|
|
62
|
+
p("SI", [[8, 6]], [8, 6]),
|
|
63
|
+
p("KY", [[7, 6]], [7, 6]),
|
|
64
|
+
p("OS", [[9, 6]], [9, 6]),
|
|
65
|
+
p("HG", [[7, 5], [8, 5]], [7, 5]),
|
|
66
|
+
p("NR", [[9, 7]], [9, 7]),
|
|
67
|
+
p("WA", [[10, 7]], [10, 7]),
|
|
68
|
+
// ── 中国 ──
|
|
69
|
+
p("TT", [[7, 4]], [7, 4]),
|
|
70
|
+
p("SM", [[7, 3]], [7, 3]),
|
|
71
|
+
p("OY", [[8, 4]], [8, 4]),
|
|
72
|
+
p("HS", [[8, 3]], [8, 3]),
|
|
73
|
+
p("YA", [[8, 2]], [8, 2]),
|
|
74
|
+
// ── 四国 ──
|
|
75
|
+
p("TK", [[11, 5]], [11, 5]),
|
|
76
|
+
p("KA", [[10, 5]], [10, 5]),
|
|
77
|
+
p("EH", [[10, 4]], [10, 4]),
|
|
78
|
+
p("KO", [[11, 3], [11, 4]], [11, 3]),
|
|
79
|
+
// ── 九州 ──
|
|
80
|
+
p("FO", [[9, 2]], [9, 2]),
|
|
81
|
+
p("SG", [[9, 1]], [9, 1]),
|
|
82
|
+
p("NS", [[9, 0]], [9, 0]),
|
|
83
|
+
p("KU", [[10, 1]], [10, 1]),
|
|
84
|
+
p("OI", [[10, 2]], [10, 2]),
|
|
85
|
+
p("MZ", [[11, 2]], [11, 2]),
|
|
86
|
+
p("KG", [[11, 1]], [11, 1]),
|
|
87
|
+
// ── 沖縄 ──
|
|
88
|
+
p("OK", [[4, 0]], [4, 0]),
|
|
89
|
+
];
|
|
90
|
+
/** All prefecture IDs in definition order */
|
|
91
|
+
exports.ALL_PREF_IDS = exports.PREF_PLACEMENTS.map((pp) => pp.id);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderMinimapForEvent = exports.shouldShowMinimap = exports.buildMinimapCells = exports.renderMinimap = exports.GRID_COLS = exports.GRID_ROWS = exports.ALL_PREF_IDS = exports.PREF_PLACEMENTS = exports.mapAreaToPref = exports.PREF_DEFS = void 0;
|
|
4
|
+
var pref_mapping_1 = require("./pref-mapping");
|
|
5
|
+
Object.defineProperty(exports, "PREF_DEFS", { enumerable: true, get: function () { return pref_mapping_1.PREF_DEFS; } });
|
|
6
|
+
Object.defineProperty(exports, "mapAreaToPref", { enumerable: true, get: function () { return pref_mapping_1.mapAreaToPref; } });
|
|
7
|
+
var grid_layout_1 = require("./grid-layout");
|
|
8
|
+
Object.defineProperty(exports, "PREF_PLACEMENTS", { enumerable: true, get: function () { return grid_layout_1.PREF_PLACEMENTS; } });
|
|
9
|
+
Object.defineProperty(exports, "ALL_PREF_IDS", { enumerable: true, get: function () { return grid_layout_1.ALL_PREF_IDS; } });
|
|
10
|
+
Object.defineProperty(exports, "GRID_ROWS", { enumerable: true, get: function () { return grid_layout_1.GRID_ROWS; } });
|
|
11
|
+
Object.defineProperty(exports, "GRID_COLS", { enumerable: true, get: function () { return grid_layout_1.GRID_COLS; } });
|
|
12
|
+
var minimap_renderer_1 = require("./minimap-renderer");
|
|
13
|
+
Object.defineProperty(exports, "renderMinimap", { enumerable: true, get: function () { return minimap_renderer_1.renderMinimap; } });
|
|
14
|
+
Object.defineProperty(exports, "buildMinimapCells", { enumerable: true, get: function () { return minimap_renderer_1.buildMinimapCells; } });
|
|
15
|
+
Object.defineProperty(exports, "shouldShowMinimap", { enumerable: true, get: function () { return minimap_renderer_1.shouldShowMinimap; } });
|
|
16
|
+
Object.defineProperty(exports, "renderMinimapForEvent", { enumerable: true, get: function () { return minimap_renderer_1.renderMinimapForEvent; } });
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.renderMinimap = renderMinimap;
|
|
7
|
+
exports.buildMinimapCells = buildMinimapCells;
|
|
8
|
+
exports.shouldShowMinimap = shouldShowMinimap;
|
|
9
|
+
exports.renderMinimapForEvent = renderMinimapForEvent;
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const formatter_1 = require("../formatter");
|
|
12
|
+
const grid_layout_1 = require("./grid-layout");
|
|
13
|
+
const pref_mapping_1 = require("./pref-mapping");
|
|
14
|
+
// ── Constants ──
|
|
15
|
+
/** Width of a single cell including trailing space: "AA:xx " = 6 chars */
|
|
16
|
+
const CELL_WIDTH = 6;
|
|
17
|
+
/** Continuation marker for multi-cell prefectures */
|
|
18
|
+
const CONTINUATION = "·····";
|
|
19
|
+
// ── Legend ──
|
|
20
|
+
/** Intensity values in display order */
|
|
21
|
+
const INTENSITY_LEGEND = ["1", "2", "3", "4", "5-", "5+", "6-", "6+", "7"];
|
|
22
|
+
/** Tsunami abbreviations in display order */
|
|
23
|
+
const TSUNAMI_LEGEND = [
|
|
24
|
+
{ abbrev: "MJ", label: "MJ", color: chalk_1.default.redBright },
|
|
25
|
+
{ abbrev: "WN", label: "WN", color: chalk_1.default.red },
|
|
26
|
+
{ abbrev: "AD", label: "AD", color: chalk_1.default.yellow },
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Build legend lines to overlay in the upper-left empty area.
|
|
30
|
+
* Returns an array of { row, text } for rows 0-3.
|
|
31
|
+
*/
|
|
32
|
+
function buildLegend() {
|
|
33
|
+
const lines = [];
|
|
34
|
+
// Row 0: "震度:" header + first 4 values
|
|
35
|
+
const intLine1 = INTENSITY_LEGEND.slice(0, 4)
|
|
36
|
+
.map((v) => (0, formatter_1.intensityColor)(v)(v.padEnd(2)))
|
|
37
|
+
.join(" ");
|
|
38
|
+
lines.push({ row: 0, text: `震度: ${intLine1}` });
|
|
39
|
+
// Row 1: next 4 values
|
|
40
|
+
const intLine2 = INTENSITY_LEGEND.slice(4, 8)
|
|
41
|
+
.map((v) => (0, formatter_1.intensityColor)(v)(v.padEnd(2)))
|
|
42
|
+
.join(" ");
|
|
43
|
+
lines.push({ row: 1, text: ` ${intLine2}` });
|
|
44
|
+
// Row 2: last value (7)
|
|
45
|
+
const intLine3 = (0, formatter_1.intensityColor)("7")("7 ");
|
|
46
|
+
lines.push({ row: 2, text: ` ${intLine3}` });
|
|
47
|
+
// Row 3: tsunami header + values
|
|
48
|
+
const tsunamiText = TSUNAMI_LEGEND.map((t) => t.color(t.label)).join(" ");
|
|
49
|
+
lines.push({ row: 3, text: `津波: ${tsunamiText}` });
|
|
50
|
+
return lines;
|
|
51
|
+
}
|
|
52
|
+
// ── ANSI strip helper ──
|
|
53
|
+
function stripAnsi(str) {
|
|
54
|
+
// eslint-disable-next-line no-control-regex
|
|
55
|
+
return str.replace(/\u001b\[[0-9;]*m/g, "");
|
|
56
|
+
}
|
|
57
|
+
// ── Rendering ──
|
|
58
|
+
/**
|
|
59
|
+
* Render the minimap from a set of cells.
|
|
60
|
+
* Returns 12 lines of text representing the ASCII minimap with legend overlay.
|
|
61
|
+
*/
|
|
62
|
+
function renderMinimap(cells) {
|
|
63
|
+
// Build cell lookup
|
|
64
|
+
const cellMap = new Map();
|
|
65
|
+
for (const cell of cells) {
|
|
66
|
+
cellMap.set(cell.prefId, cell);
|
|
67
|
+
}
|
|
68
|
+
// Build placement lookup: (row,col) -> { prefId, isAnchor }
|
|
69
|
+
const gridMap = new Map();
|
|
70
|
+
for (const placement of grid_layout_1.PREF_PLACEMENTS) {
|
|
71
|
+
for (const pos of placement.cells) {
|
|
72
|
+
const key = `${pos.row},${pos.col}`;
|
|
73
|
+
gridMap.set(key, {
|
|
74
|
+
prefId: placement.id,
|
|
75
|
+
isAnchor: pos.row === placement.anchor.row && pos.col === placement.anchor.col,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Build legend
|
|
80
|
+
const legend = buildLegend();
|
|
81
|
+
const legendByRow = new Map();
|
|
82
|
+
for (const entry of legend) {
|
|
83
|
+
legendByRow.set(entry.row, entry.text);
|
|
84
|
+
}
|
|
85
|
+
// Render each row
|
|
86
|
+
const lines = [];
|
|
87
|
+
for (let row = 0; row < grid_layout_1.GRID_ROWS; row++) {
|
|
88
|
+
let line = "";
|
|
89
|
+
// Find the last occupied column in this row
|
|
90
|
+
let lastCol = -1;
|
|
91
|
+
for (let col = 0; col < grid_layout_1.GRID_COLS; col++) {
|
|
92
|
+
if (gridMap.has(`${row},${col}`))
|
|
93
|
+
lastCol = col;
|
|
94
|
+
}
|
|
95
|
+
for (let col = 0; col < grid_layout_1.GRID_COLS; col++) {
|
|
96
|
+
const key = `${row},${col}`;
|
|
97
|
+
const entry = gridMap.get(key);
|
|
98
|
+
if (entry == null) {
|
|
99
|
+
// Empty cell (ocean) — check if legend should be rendered here
|
|
100
|
+
if (legendByRow.has(row) && col === 0) {
|
|
101
|
+
const legendText = legendByRow.get(row);
|
|
102
|
+
line += legendText;
|
|
103
|
+
// Calculate how many columns the legend text spans
|
|
104
|
+
const legendVisualLen = stripAnsi(legendText).length;
|
|
105
|
+
const colsSpanned = Math.ceil(legendVisualLen / CELL_WIDTH);
|
|
106
|
+
col += colsSpanned - 1; // skip ahead (loop will increment)
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (col <= lastCol) {
|
|
110
|
+
line += " ".repeat(CELL_WIDTH);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const cell = cellMap.get(entry.prefId);
|
|
115
|
+
const content = cell?.content ?? "..";
|
|
116
|
+
const isMatch = content !== "..";
|
|
117
|
+
if (entry.isAnchor) {
|
|
118
|
+
// Anchor cell: show "AA:xx"
|
|
119
|
+
const padded = content.length >= 2 ? content.slice(0, 2) : content.padEnd(2);
|
|
120
|
+
const text = `${entry.prefId}:${padded}`;
|
|
121
|
+
if (isMatch && cell?.color) {
|
|
122
|
+
line += cell.color(text) + " ";
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
line += chalk_1.default.dim(text) + " ";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Continuation cell: show "·····"
|
|
130
|
+
if (isMatch && cell?.color) {
|
|
131
|
+
line += cell.color(CONTINUATION) + " ";
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
line += chalk_1.default.dim(CONTINUATION) + " ";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
lines.push(line.trimEnd());
|
|
140
|
+
}
|
|
141
|
+
return lines;
|
|
142
|
+
}
|
|
143
|
+
// ── Building cells from PresentationEvent ──
|
|
144
|
+
/** Tsunami warning kind abbreviations */
|
|
145
|
+
function tsunamiKindAbbrev(kind) {
|
|
146
|
+
if (kind.includes("大津波"))
|
|
147
|
+
return "MJ";
|
|
148
|
+
if (kind.includes("津波警報"))
|
|
149
|
+
return "WN";
|
|
150
|
+
if (kind.includes("注意報"))
|
|
151
|
+
return "AD";
|
|
152
|
+
return "??";
|
|
153
|
+
}
|
|
154
|
+
/** Tsunami warning color by abbreviation */
|
|
155
|
+
function tsunamiColor(abbrev) {
|
|
156
|
+
switch (abbrev) {
|
|
157
|
+
case "MJ":
|
|
158
|
+
return chalk_1.default.redBright;
|
|
159
|
+
case "WN":
|
|
160
|
+
return chalk_1.default.red;
|
|
161
|
+
case "AD":
|
|
162
|
+
return chalk_1.default.yellow;
|
|
163
|
+
default:
|
|
164
|
+
return chalk_1.default.white;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** Tsunami kind priority (higher = more severe) */
|
|
168
|
+
function tsunamiKindPriority(abbrev) {
|
|
169
|
+
switch (abbrev) {
|
|
170
|
+
case "MJ":
|
|
171
|
+
return 3;
|
|
172
|
+
case "WN":
|
|
173
|
+
return 2;
|
|
174
|
+
case "AD":
|
|
175
|
+
return 1;
|
|
176
|
+
default:
|
|
177
|
+
return 0;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Build MinimapCell[] from a PresentationEvent.
|
|
182
|
+
* Assigns prefecture-level data (max intensity, tsunami kind) for each matched area.
|
|
183
|
+
*/
|
|
184
|
+
function buildMinimapCells(event) {
|
|
185
|
+
const prefData = new Map();
|
|
186
|
+
if (event.domain === "earthquake" || event.domain === "lgObservation" || event.domain === "eew") {
|
|
187
|
+
for (const item of event.areaItems) {
|
|
188
|
+
const prefId = (0, pref_mapping_1.mapAreaToPref)(item.name);
|
|
189
|
+
if (prefId == null)
|
|
190
|
+
continue;
|
|
191
|
+
const maxInt = item.maxInt ?? "..";
|
|
192
|
+
const rank = maxInt !== ".." ? (0, formatter_1.intensityToNumeric)(maxInt) : -1;
|
|
193
|
+
const existing = prefData.get(prefId);
|
|
194
|
+
if (!existing || rank > existing.priority) {
|
|
195
|
+
prefData.set(prefId, {
|
|
196
|
+
content: maxInt,
|
|
197
|
+
color: maxInt !== ".." ? (0, formatter_1.intensityColor)(maxInt) : undefined,
|
|
198
|
+
priority: rank,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else if (event.domain === "tsunami") {
|
|
204
|
+
for (const item of event.areaItems) {
|
|
205
|
+
const prefId = (0, pref_mapping_1.mapAreaToPref)(item.name);
|
|
206
|
+
if (prefId == null)
|
|
207
|
+
continue;
|
|
208
|
+
const kind = item.kind ?? "";
|
|
209
|
+
const abbrev = tsunamiKindAbbrev(kind);
|
|
210
|
+
const priority = tsunamiKindPriority(abbrev);
|
|
211
|
+
const existing = prefData.get(prefId);
|
|
212
|
+
if (!existing || priority > existing.priority) {
|
|
213
|
+
prefData.set(prefId, {
|
|
214
|
+
content: abbrev,
|
|
215
|
+
color: tsunamiColor(abbrev),
|
|
216
|
+
priority,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Build cells for all prefectures
|
|
222
|
+
const cells = [];
|
|
223
|
+
for (const prefId of grid_layout_1.ALL_PREF_IDS) {
|
|
224
|
+
const data = prefData.get(prefId);
|
|
225
|
+
if (data) {
|
|
226
|
+
cells.push({ prefId, content: data.content, color: data.color });
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
cells.push({ prefId, content: ".." });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return cells;
|
|
233
|
+
}
|
|
234
|
+
// ── Display conditions ──
|
|
235
|
+
/**
|
|
236
|
+
* Determine whether the minimap should be shown for this event.
|
|
237
|
+
*/
|
|
238
|
+
function shouldShowMinimap(event) {
|
|
239
|
+
const termWidth = process.stdout.columns ?? 80;
|
|
240
|
+
if (termWidth < 80)
|
|
241
|
+
return false;
|
|
242
|
+
if (event.isCancellation)
|
|
243
|
+
return false;
|
|
244
|
+
switch (event.domain) {
|
|
245
|
+
case "earthquake": {
|
|
246
|
+
if (event.areaCount === 0)
|
|
247
|
+
return false;
|
|
248
|
+
const rank = event.maxIntRank ?? 0;
|
|
249
|
+
return rank >= 4 || event.areaCount >= 4;
|
|
250
|
+
}
|
|
251
|
+
case "eew":
|
|
252
|
+
return event.forecastAreaCount > 0;
|
|
253
|
+
case "tsunami":
|
|
254
|
+
if (event.forecastAreaCount === 0 && event.areaCount === 0)
|
|
255
|
+
return false;
|
|
256
|
+
return ["critical", "warning", "normal"].includes(event.frameLevel);
|
|
257
|
+
case "lgObservation": {
|
|
258
|
+
if (event.areaCount === 0 && event.observationCount === 0)
|
|
259
|
+
return false;
|
|
260
|
+
const rank = event.maxIntRank ?? 0;
|
|
261
|
+
const count = event.observationCount > 0 ? event.observationCount : event.areaCount;
|
|
262
|
+
return rank >= 4 || count >= 4;
|
|
263
|
+
}
|
|
264
|
+
default:
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Public API: render the minimap for a PresentationEvent.
|
|
270
|
+
* Returns the minimap lines, or null if the minimap should not be shown.
|
|
271
|
+
*/
|
|
272
|
+
function renderMinimapForEvent(event) {
|
|
273
|
+
if (!shouldShowMinimap(event))
|
|
274
|
+
return null;
|
|
275
|
+
const cells = buildMinimapCells(event);
|
|
276
|
+
return renderMinimap(cells);
|
|
277
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PREF_DEFS = void 0;
|
|
4
|
+
exports.mapAreaToPref = mapAreaToPref;
|
|
5
|
+
/** All 47 prefecture definitions with match patterns */
|
|
6
|
+
exports.PREF_DEFS = [
|
|
7
|
+
{ id: "HK", name: "北海道", patterns: ["北海道"] },
|
|
8
|
+
{ id: "AO", name: "青森県", patterns: ["青森"] },
|
|
9
|
+
{ id: "IT", name: "岩手県", patterns: ["岩手"] },
|
|
10
|
+
{ id: "MG", name: "宮城県", patterns: ["宮城"] },
|
|
11
|
+
{ id: "AK", name: "秋田県", patterns: ["秋田"] },
|
|
12
|
+
{ id: "YG", name: "山形県", patterns: ["山形"] },
|
|
13
|
+
{ id: "FS", name: "福島県", patterns: ["福島"] },
|
|
14
|
+
{ id: "IB", name: "茨城県", patterns: ["茨城"] },
|
|
15
|
+
{ id: "TC", name: "栃木県", patterns: ["栃木"] },
|
|
16
|
+
{ id: "GU", name: "群馬県", patterns: ["群馬"] },
|
|
17
|
+
{ id: "ST", name: "埼玉県", patterns: ["埼玉"] },
|
|
18
|
+
{ id: "CB", name: "千葉県", patterns: ["千葉"] },
|
|
19
|
+
{ id: "TY", name: "東京都", patterns: ["東京島しょ", "小笠原", "東京"] },
|
|
20
|
+
{ id: "KN", name: "神奈川県", patterns: ["神奈川"] },
|
|
21
|
+
{ id: "NI", name: "新潟県", patterns: ["新潟"] },
|
|
22
|
+
{ id: "TM", name: "富山県", patterns: ["富山"] },
|
|
23
|
+
{ id: "IS", name: "石川県", patterns: ["石川"] },
|
|
24
|
+
{ id: "FI", name: "福井県", patterns: ["福井"] },
|
|
25
|
+
{ id: "YN", name: "山梨県", patterns: ["山梨"] },
|
|
26
|
+
{ id: "NA", name: "長野県", patterns: ["長野"] },
|
|
27
|
+
{ id: "GI", name: "岐阜県", patterns: ["岐阜"] },
|
|
28
|
+
{ id: "SZ", name: "静岡県", patterns: ["静岡"] },
|
|
29
|
+
{ id: "AI", name: "愛知県", patterns: ["愛知"] },
|
|
30
|
+
{ id: "ME", name: "三重県", patterns: ["三重"] },
|
|
31
|
+
{ id: "SI", name: "滋賀県", patterns: ["滋賀"] },
|
|
32
|
+
{ id: "KY", name: "京都府", patterns: ["京都"] },
|
|
33
|
+
{ id: "OS", name: "大阪府", patterns: ["大阪"] },
|
|
34
|
+
{ id: "HG", name: "兵庫県", patterns: ["兵庫"] },
|
|
35
|
+
{ id: "NR", name: "奈良県", patterns: ["奈良"] },
|
|
36
|
+
{ id: "WA", name: "和歌山県", patterns: ["和歌山"] },
|
|
37
|
+
{ id: "TT", name: "鳥取県", patterns: ["鳥取"] },
|
|
38
|
+
{ id: "SM", name: "島根県", patterns: ["島根"] },
|
|
39
|
+
{ id: "OY", name: "岡山県", patterns: ["岡山"] },
|
|
40
|
+
{ id: "HS", name: "広島県", patterns: ["広島"] },
|
|
41
|
+
{ id: "YA", name: "山口県", patterns: ["山口"] },
|
|
42
|
+
{ id: "TK", name: "徳島県", patterns: ["徳島"] },
|
|
43
|
+
{ id: "KA", name: "香川県", patterns: ["香川"] },
|
|
44
|
+
{ id: "EH", name: "愛媛県", patterns: ["愛媛"] },
|
|
45
|
+
{ id: "KO", name: "高知県", patterns: ["高知"] },
|
|
46
|
+
{ id: "FO", name: "福岡県", patterns: ["福岡"] },
|
|
47
|
+
{ id: "SG", name: "佐賀県", patterns: ["佐賀"] },
|
|
48
|
+
{ id: "NS", name: "長崎県", patterns: ["長崎"] },
|
|
49
|
+
{ id: "KU", name: "熊本県", patterns: ["熊本"] },
|
|
50
|
+
{ id: "OI", name: "大分県", patterns: ["大分"] },
|
|
51
|
+
{ id: "MZ", name: "宮崎県", patterns: ["宮崎"] },
|
|
52
|
+
{ id: "KG", name: "鹿児島県", patterns: ["奄美", "鹿児島"] },
|
|
53
|
+
{ id: "OK", name: "沖縄県", patterns: ["沖縄"] },
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Build a sorted pattern index: longer patterns first to prevent false matches.
|
|
57
|
+
* e.g. "東京島しょ" is checked before "東京".
|
|
58
|
+
*/
|
|
59
|
+
function buildPatternIndex() {
|
|
60
|
+
const entries = [];
|
|
61
|
+
for (const def of exports.PREF_DEFS) {
|
|
62
|
+
for (const pattern of def.patterns) {
|
|
63
|
+
entries.push({ pattern, prefId: def.id });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
entries.sort((a, b) => b.pattern.length - a.pattern.length);
|
|
67
|
+
return entries;
|
|
68
|
+
}
|
|
69
|
+
const patternIndex = buildPatternIndex();
|
|
70
|
+
/**
|
|
71
|
+
* Map an area name (e.g. "石川県能登地方") to its prefecture ID.
|
|
72
|
+
* Uses substring matching with longer patterns checked first.
|
|
73
|
+
* Returns null if no match is found.
|
|
74
|
+
*/
|
|
75
|
+
function mapAreaToPref(areaName) {
|
|
76
|
+
for (const { pattern, prefId } of patternIndex) {
|
|
77
|
+
if (areaName.includes(pattern)) {
|
|
78
|
+
return prefId;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyNightOverlay = applyNightOverlay;
|
|
4
|
+
exports.getExemptRoles = getExemptRoles;
|
|
5
|
+
/**
|
|
6
|
+
* Night mode overlay: chalk.dim 相当の減光を ResolvedStyle に適用する。
|
|
7
|
+
* 危険色ロールは減光対象外とし、視認性を維持する。
|
|
8
|
+
*/
|
|
9
|
+
/** 減光を適用しないロール一覧 (critical 級の危険色) */
|
|
10
|
+
const EXEMPT_ROLES = new Set([
|
|
11
|
+
"frameCritical",
|
|
12
|
+
"tsunamiMajor",
|
|
13
|
+
"eewWarningBanner",
|
|
14
|
+
"volcanoFlashBanner",
|
|
15
|
+
"intensity6Upper",
|
|
16
|
+
"intensity7",
|
|
17
|
+
]);
|
|
18
|
+
/** RGB 値を減光する (輝度を約50%に落とす) */
|
|
19
|
+
function dimRgb(rgb) {
|
|
20
|
+
return [
|
|
21
|
+
Math.round(rgb[0] * 0.5),
|
|
22
|
+
Math.round(rgb[1] * 0.5),
|
|
23
|
+
Math.round(rgb[2] * 0.5),
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
/** 単一スタイルに dim を適用する */
|
|
27
|
+
function dimStyle(style) {
|
|
28
|
+
return {
|
|
29
|
+
fg: style.fg ? dimRgb(style.fg) : undefined,
|
|
30
|
+
bg: style.bg ? dimRgb(style.bg) : undefined,
|
|
31
|
+
bold: style.bold,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* ResolvedTheme に night overlay を適用して新しい ResolvedTheme を返す。
|
|
36
|
+
* 元のテーマは変更しない (純粋関数)。
|
|
37
|
+
*/
|
|
38
|
+
function applyNightOverlay(theme) {
|
|
39
|
+
// パレットも減光
|
|
40
|
+
const palette = { ...theme.palette };
|
|
41
|
+
for (const key of Object.keys(palette)) {
|
|
42
|
+
palette[key] = dimRgb(palette[key]);
|
|
43
|
+
}
|
|
44
|
+
// ロールスタイルを減光 (危険色ロールは除外)
|
|
45
|
+
const roles = { ...theme.roles };
|
|
46
|
+
for (const key of Object.keys(roles)) {
|
|
47
|
+
if (!EXEMPT_ROLES.has(key)) {
|
|
48
|
+
roles[key] = dimStyle(roles[key]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { palette, roles };
|
|
52
|
+
}
|
|
53
|
+
/** 減光対象外のロール名一覧を返す (テスト用) */
|
|
54
|
+
function getExemptRoles() {
|
|
55
|
+
return EXEMPT_ROLES;
|
|
56
|
+
}
|