-
Notifications
You must be signed in to change notification settings - Fork 7
Suspicious Logic
niryuu edited this page May 25, 2026
·
1 revision
このファイルの前提:
ここに挙げる項目は仕様の正解が不明、現に動いているものを正と看做す。
長年積み重なった embed コードベースには、なぜそうなっているのか説明しにくい分岐・ハードコード・非対称な条件がある。書き直しの際にこれらを「現状維持」「修正」「再設計」のいずれに振るか判断するための材料として、各項目に 場所・現状・不明点・リスク を記録する。
-
場所:
geolonia-map.ts:156-158 -
現状:
dev stage のとき
if (atts.stage === 'dev' && transformedUrlObj.hostname === 'tileserver.geolonia.com') { transformedUrlObj.hostname = 'tileserver-dev.geolonia.com'; }
tileserver.geolonia.comのみtileserver-dev.geolonia.comに置換。 -
不明点:
-
*.tiles.geolonia.com(osm.v3 等) は dev でも置換されない。サーバ側に対応する dev サブドメインがあるのか? 無いなら dev 用の OSM タイルは無い? - sprite URL は別ロジック (
geolonia-map.ts:171のpathParts[1]置換) で対称性が無い
-
-
リスク: dev stage で
osm.v3.tiles.geolonia.comを使うとプロダクション同じホストに行く → 認証失敗 or 古いデータ - 対応案: サーバ側仕様を確認のうえ全 Geolonia ホストで dev 置換を統一するか、現状の特殊扱いを明文化する
-
場所:
util.ts:38-50 -
現状:
コメント:
return ( urlObj.hostname === 'tileserver.geolonia.com' || urlObj.hostname.endsWith('.tiles.geolonia.com') );
// NOTE: geolonia use tileserver.geolonia.com or *.tiles.geolonia.com for tile server. Other domains is NOT allowed. -
不明点:
- 新タイルサーバ追加時の運用 (例:
tileserver-v2.geolonia.com,*.maps.geolonia.com等の予定) - cdn.geolonia.com (スタイル) はここに含まれない (transformRequest 対象でないため。スタイル JSON は public、認証不要)
- 新タイルサーバ追加時の運用 (例:
- リスク: 新ホスト追加時にこの関数を修正し忘れると認証注入されず実 fetch が失敗
- 対応案: 環境変数 / ビルド時定数 / サーバ側 manifest から動的取得 (大袈裟か検討)
-
場所:
util.ts:67-105 - 現状: 3 サイトに対し referrer prefix を hardcode。新サイト (StackBlitz, JS Bin, etc.) は許可されない
-
不明点:
- 過去にどういう経緯でこの 3 サイトが追加されたか (issue 履歴に残っているはず)
- 将来追加可能性のあるサイト
- リスク: メンテナンス負担。新サイトユーザに「動かない」と問い合わせ来る
- 対応案: ホワイトリストを設定ファイル化 or サーバ側で管理してロード時に取得
-
場所:
keyring.ts:102-131 -
現状: 空文字 → URL prefix 2 種 → 一般 URL →
.json終端 → 論理名 の順で判定 -
不明点:
-
境界条件:
'./foo.json'で location.host がgeolonia.comを含む場合と含まない場合で結果が変わる -
'foo'(拡張子なし、URL でない) は論理名扱い → 任意の文字列が Geolonia 判定 → API key 必須化 -
'geolonia.com/foo'(スキームなし) も URL 扱いされず論理名扱い
-
境界条件:
-
リスク:
- 誤って Geolonia 扱いされた外部スタイルで API key 強制 → ユーザが key なくて使えない
- 誤って外部扱いされた Geolonia スタイルで認証注入されず 401 / 403
-
対応案: 仕様を整理して decision table を文書化 (
Data-Attributesの "data-style" 参照)、エッジケースのテスト追加
-
場所:
util.ts:217-273(getStyle) vskeyring.ts:102-131(isGeoloniaStyleCheck) -
現状: 両者で別々のロジックで「style 文字列を解釈」している
-
getStyle: URL に変換 (空 / 絶対 URL / 相対 /.json/ 論理名 の 5 分岐) -
isGeoloniaStyleCheck: Geolonia 判定 (5 分岐、上記)
-
-
不明点: 両者の分岐が完全に同期しているか不明 — 例えば「論理名
'foo'」を getStyle はhttps://cdn.geolonia.com/style/foo/{lang}.jsonに解決し、isGeoloniaStyleCheck は Geolonia 扱い (true)。一致するが微妙な境界 (例: relative URL かつ host に geolonia.com 含まない) でズレる可能性 - リスク: ロジック齟齬で UNDEFINED 挙動
-
対応案: 1 つの decision table から両方を生成 (共通関数
categorizeStyle(style) → 'default' | 'absolute-url' | 'relative-json' | 'logical-name')
-
場所:
render.ts:67-80 -
現状: 初回 isIntersecting=true で
renderSingleMap+unobserve。再度 viewport に入ってもマップ再生成しない - 不明点: 意図的か (lazy-load の本来の意味: 一度ロードしたら保持) バグか (一度離れたら map を破棄して再表示で再構築すべき) は仕様 unclear
-
リスク: 長いページで多数の
.geoloniaがある場合、メモリ使用量が累積 -
対応案: 現状維持で問題ない場合が多い。明示的に再表示で再構築したいなら
observer.observeを再度呼ぶ運用に
-
場所:
render.ts:37-45 -
現状:
observer.observe(target.parentNode, { childList: true })。target 自身ではなく親要素を監視。removedNodes に target が含まれたら map.remove() -
不明点:
- target の親自身が削除された場合は検知できない (親より上の祖先削除を見ない)
- target が他の親に moveTo された場合の挙動 (MutationObserver は新親では fire しない)
- リスク: 親要素ごと消える典型ケース (例: React のコンポーネントツリー unmount) で map が remove されずメモリリーク
-
対応案:
MutationObserverの代わりにtarget.isConnectedを定期的に check するか、React 等で明示的にmap.remove()を呼ぶ運用に倒す
-
場所:
render.ts:47-65 -
現状:
- DOMContentLoaded 前:
alreadyRenderedMapsにキュー - DOMContentLoaded ハンドラで一括実行
- 各 plugin に同じ
attsを渡す (renderSingleMap 時点のスナップショット)
- DOMContentLoaded 前:
-
不明点:
- プラグインが内部で非同期処理を持つ場合、map.on('load') の前後で何が保証されているか
- 同じ plugin が
registerPluginで複数回登録された場合の意図 (現状は重複実行)
- リスク: プラグインが marker 等を追加する場合、map.on('load') を待たずに addLayer を呼ぶと失敗
-
対応案: プラグインに「load 後に呼ばれる」契約を明示。
map.on('load')内で plugin を呼ぶ設計に変える案も
-
場所:
simplestyle-vector.ts全体 -
現状:
addTo内でmap.on('sourcedata', ...)で listener を永続登録するが、remove()メソッドが存在しない - 不明点: 単純な実装漏れか、意図的か (map.remove() で十分?)
-
リスク: 同一マップで
SimpleStyleVectorを再 addTo すると listener 二重登録、メモリリーク -
対応案: GeoJSON 版と同様
_eventHandlers配列で管理しremove()を追加
-
場所:
geolonia-map.ts:242-247 -
現状:
if (atts.loader !== 'off') { try { container.removeChild(loading); } catch { // Nothing to do. } }
-
不明点:
loadingは同じ constructor でcontainer.appendChild(loading)したばかり。なぜ削除が失敗しうる?- 可能性 1: ユーザコードが loader を消した
- 可能性 2:
super(options)が container.innerHTML を上書きした (まさかとは思うが) - 可能性 3: 過去のバグの安全弁が残っている
- リスク: 現状動いているが、根本原因不明のまま try-catch でスタックが食われる
- 対応案: 削除失敗の根本原因を調査、不要なら try-catch を外す
-
場所:
util.ts:299-303 -
現状:
if (atts.minZoom !== '' && (Number(atts.minZoom) === 0 || Number(atts.minZoom))) { options.minZoom = Number(atts.minZoom); }
-
不明点: なぜ
=== 0分岐が必要?-
Number('')は0なので、!== ''ガードで弾く必要 -
Number('0') === 0、Number('foo') === NaN、Number('5') === 5 -
Number(atts.minZoom)だけだと0が falsy で弾かれてしまう ('0'文字列が許容されない) - つまりこの冗長条件は「
'0'を許容しつつ''と NaN を弾く」意図
-
- リスク: なし (現状動作する)
-
対応案: コメントを追加するか、
Number.isFinite(Number(atts.minZoom))の方が明確
-
場所:
geolonia-map.ts:164-177 -
現状:
if ( (resourceType === 'SpriteJSON' || resourceType === 'SpriteImage') && transformedUrl.match(/^https:\/\/api\.geolonia\.com\/(dev|v1)\/sprites\//) ) { const pathParts = transformedUrlObj.pathname.split('/'); pathParts[1] = String(atts.stage); transformedUrlObj.pathname = pathParts.join('/'); // ... }
-
不明点:
- pathname 構造
/dev/sprites/...または/v1/sprites/...に強く依存 -
pathParts[0]=''(先頭スラッシュの前)、pathParts[1]= stage、pathParts[2]='sprites'、以下続く - サーバ側の URL 仕様が変わると壊れる
- pathname 構造
-
リスク: サーバ側で
/v2/sprites/...構造が変わると embed が動かなくなる -
対応案: URL の置換ではなくテンプレート化 (
https://api.geolonia.com/${stage}/sprites/${originalPathParts.slice(2).join('/')}等)
-
場所:
util.ts:337-356 -
現状: モジュール変数
sessionIdにキャッシュ。1 度生成したら page life で固定 - 不明点: 複数 GeoloniaMap インスタンス間で session を共有する意図 (アクセス集計の都合?)
-
リスク:
- Web Worker / 別 iframe で別 module instance になる → 別 session ID
- sessionStorage / localStorage に書かないので reload で別 ID (これは意図通り?)
- 対応案: 現状で問題ない。複数マップで同じ session 集計したいなら仕様として明文化
-
場所:
util.ts:282-284 -
現状:
if (params === container) { params = {}; }
-
不明点:
paramsとcontainerが同一の HTMLElement になるケース?-
new GeoloniaMap(htmlElement)のときに上層でparseAtts(container, { interactive })を呼んでからgetOptions(container, params, atts)に進むが、paramsには{ interactive: true/false }が入っているはず (geolonia-map.ts:97-100) - 直接
new GeoloniaMap(htmlElement)で呼ばれてparamsが HTMLElement になる経路はない - もしかすると古い API で
getOptions(container, htmlElement, atts)のように呼んでいた名残?
-
- リスク: なし (defensive code)
- 対応案: 呼び出し経路を整理して不要なら削除
-
場所:
parse-atts.ts:41('#E4402F'),geolonia-marker.ts:40('#E4402F')、parse-atts.ts:54('#ff0000'),simplestyle.ts:33('#ff0000') - 現状: 同じ literal が 2 箇所で独立に定義
- リスク: 一方を変更したら他方が追従しない → デザインが分裂する
-
対応案:
constants.tsのような共通モジュールに移す
-
場所:
webpack.config.js:7,keyring.ts:73 -
現状: webpack DefinePlugin で
process.env.MAP_PLATFORM_STAGEを JS リテラルに静的置換 - 不明点: ランタイム可変にする意図がなかった理由 (セキュリティ?最適化?)
- リスク: 同じバンドルを dev/v1 で使い回せない → 2 種類ビルドする必要
-
対応案:
embed-core化で lib として複数環境で使うなら、ランタイム設定可能化を検討
-
場所:
simplestyle.ts:32 -
現状:
heatmap: false, // TODO: It should support heatmap. - 対応案: 実装するか TODO を削除するか判断。実装しないなら option 自体を削除推奨
-
場所:
simplestyle.ts:30(id: 'geolonia-simple-style') -
現状: options.id デフォルトが固定 prefix。同じマップに 2 つの SimpleStyle を addTo すると
getLayer等で衝突 -
回避策: コンストラクタ第 2 引数で
{ id: 'mydata-1' }を渡す → 別 prefix になる - 対応案: ドキュメントに明記、または自動 UUID 付与で衝突回避
-
場所:
geolonia-map.ts:327-356 -
現状: styledata イベントで
style.layers.forEach((layer) => {...})で全レイヤを走査し metadata チェック - 不明点: zoom / pan / setData 等でも styledata が fire するため、頻繁に走査が走る可能性
- リスク: 大規模スタイル (数百レイヤ) でパフォーマンス影響
-
対応案:
__styleExtensionLoadRequiredフラグで 1 度限りに guard されているため現状は深刻でない (geolonia-map.ts:294-297)。setStyle 後の再走査はあるが頻度低い
-
場所:
geolonia-map.ts:395 -
現状:
super.setStyle(style, options)ではなくsuper.setStyle.call(this, style, options)の形で呼ぶ -
コメント (
geolonia-map.ts:381-383):It can't access
thisbecausesetStyle()will be called withsuper(). So, we need to runparseAtts()again(?) -
不明点: maplibre の constructor 内で setStyle が呼ばれる際、
thisの bind が壊れるのか?.call(this, ...)で本当に解決されるのか? - リスク: maplibre のバージョンアップで内部実装が変わると壊れる
- 対応案: maplibre の constructor 挙動を追って、本当に必要か検証
-
場所:
parse-atts.ts:27 -
現状:
keyring.parse(container)を呼ぶが、keyring.parse(doc: Document = document)のシグネチャに HTMLElement を渡している - 不明点: 過去に意味があったか、最初から no-op だったか
- リスク: 型エラー警告は出ない (ts loose check)、実害なし
-
対応案: container 引数を削除して
keyring.parse()のみに
-
場所:
render.ts:48 -
現状:
parseAtts(target)の結果をattsとしてキューに保持、DOMContentLoaded 後の遅延実行でも同じ atts を渡す - 不明点: data-* が動的に変更されたケースで何を期待するか
-
対応案: ドキュメントで「プラグインは初期化時の atts を受け取る」と明文化、動的変更を見たければ
target.datasetを直接読む運用
-
場所:
geolonia-map.ts:202-205 -
現状:
parseControlOption(atts.geoloniaControl)の戻り値のうちpositionのみ参照、enabledを無視 -
不明点: 「Geolonia ブランディングは消せない」という仕様か、
enabledチェック忘れか -
リスク:
data-geolonia-control="off"を指定したユーザの期待を裏切る -
対応案: 仕様確認 → 仕様通りなら docs に明記、忘れなら
enabledチェック追加
-
場所:
geolonia-map.ts:140-145 -
現状: regex
^geolonia:\/\/tiles\/(?<username>.+)\/(?<customtileId>.+)の username キャプチャは使わず捨てる - 不明点: 過去 username で識別する設計だったが、現状 customtileId だけで十分という変遷
- リスク: なし (使われない情報)
- 対応案: regex から username を削るか、コメントで意図を残す
-
場所:
util.ts:405 -
現状:
export const random = (max: number): number => Math.floor(Math.random() * max); -
不明点: embed コードベース内で呼び出されていない (
util.test.tsのみ?)。外部から import される可能性は低い (embed.ts / embed-core.ts から export されていない) - 対応案: 削除候補
-
場所:
simplestyle-vector.ts:170 -
現状:
vt-circle-simple-style-pointsのみ prefix がvt-circle-、他はvt-geolonia-simple-style- - 不明点: なぜ統一されていないか
- 対応案: 統一すべきだが、外部から layer ID を直接参照する利用があるなら破壊的変更になる
-
場所:
parse-atts.ts:33-66(戻り値)、src/types.ts:3-34 -
現状:
simpleVector,stageが戻り値に含まれるがEmbedAttributes型に定義されていない。[otherKey: string]で型チェックを通している -
対応案:
EmbedAttributesに正式追加
-
場所:
embed-core.ts:11-12(import 時),render.ts:13-14(renderGeoloniaMap 内) -
現状: 両方が同じプロセスでロードされると
maplibregl.addProtocol('pmtiles', ...)を 2 回呼ぶ - 不明点: maplibre の挙動 (二重登録で error か silent overwrite か)
- リスク: 同一ページで embed.js と embed-core.js を併用するケース (稀だが React wrapper + iframe 等)
-
対応案: maplibre 仕様確認のうえ、ガード条件 (
if (!maplibregl.getProtocol('pmtiles')) ...) を追加
-
場所:
util.ts:294 - 現状: maplibre option として固定値で sans-serif を指定
-
不明点: ユーザがカスタムフォントを使いたい場合は params 経由で上書きする (
Object.assign(options, params)が後で動くため) のが想定挙動だが、明示されていない - 対応案: docs に明記
-
場所:
util.ts:386-388 - 現状: 「地図の初期化に失敗しました。管理者にお問い合わせ下さい。開発者の方は開発者ツールでエラー詳細をご確認下さい。」
- 不明点: i18n の予定 / 必要性
- 対応案: 多言語化検討 (atts.lang から切替) または英語に統一
合計 30 項目。書き直し時にこのリストを 1 つずつ評価し、「現状維持」「修正」「削除」のいずれかを決定する。