本文へ移動
Hikari 仕様

パッケージ配布 (third-party モジュール)

本書は third-party パッケージ配布 を定義する。import x := "pkg:<alias>" の解決規則の言語側は language-spec.md §13.4、CLI は hikari-command.md を参照。本書中の §N は本書内の節を指す。language-spec.md の節は明示する。

標準ライブラリ (std/index.md) が「host が同梱するモジュール」を std: で取得するのに対し、本書は「他者が配布する Hikari パッケージ」を pkg: で取得する仕組みを担う。中核思想:

  • 使う側は別名のみ — import 文には短い別名を書き、取得元・バージョンは マニフェスト 1 箇所に集中させる。
  • 分散・中央レジストリなし — 取得は git。誰でも持つ VCS をバージョン源とし、レジストリ運用を負わない。
  • 解決器なし — 各マニフェストが exact pin。バージョン範囲も衝突解消も持たず、別バージョンは共存させる。
  • 設定は宣言データ — マニフェストも lockfile も TOML で書く。依存の宣言に Hikari の表現力は要らない。

1. 概念

用語 意味
パッケージ マニフェスト (package.toml) を root に持つ .hika ソースツリー。1 つの 入口 (entry) を公開する
マニフェスト パッケージの依存 (deps) と入口 (entry) を宣言する TOML ファイル
別名 (alias) pkg:<alias> でパッケージを指す論理名。マニフェスト・ローカル (各マニフェスト内で独立)。字形は [A-Za-z0-9_-]+ (§2.3)
取得元 (source) 別名が解決する実体。git source (host/path@<tag>) または path dep (./ ../ /)
lockfile 全推移依存を tag → commit で固定した自動生成ファイル (package.lock)
キャッシュ 取得済みパッケージのグローバル格納先 ($HIKARI_CACHE)

消費側の最小例:

import { get, post } := "pkg:http"  # 別名 http の入口を引く
get "https://example.com"

http がどこの何バージョンかは、この .hika を含むパッケージのマニフェストが決める。

2. マニフェスト (package.toml)

パッケージ root に置く。中身は TOML。

entry = "src/main.hika"  # pkg:<このパッケージ> の入口

[deps]
http = "github.com/u/hikari-http@1.4.0"
log  = "../my-log"  # ローカル path dep
キー 意味
deps テーブル (alias = <source>) 別名 → 取得元の対応。空可 (テーブルごと省略してよい)
entry String pkg:<このパッケージ> を import した側が着地する入口ファイル (パッケージ root からの相対)

host はマニフェストを TOML として読み、deps / entry を取り出す。評価は行わない — マニフェストは宣言データであり、Hikari の表現力 (関数・条件分岐・参照) を必要としない。deps の宣言順は保持し、hikari add / hikari remove (hikari-command.md) の書き戻しでも崩さない。

host が読まないキー (author 等) は無視する (前方互換)。ただし無視したキーは警告として stderr に出す (format.md「未知キーの警告」と同じ扱い)。警告であり失敗させない。

package.toml: ignoring unknown key 'author'

TOML の規則により、entry のようなトップレベルのキーは [deps] テーブルよりに置く必要がある。後ろに置くと deps.entry として読まれる — これは未知キーではなく entry という名前の別名として正しく読めてしまうので、上の警告では拾えない。マニフェストは entry を欠いた不正なマニフェスト (§6) として拒み、診断が吸い込まれた先を名指しする。

2.1 取得元 (source) の記法と判別

deps の各値 (String) は先頭で 2 種に判別する:

  • path dep: 先頭が . (./ ../) または /。マニフェスト root 基準の相対 (または絶対) ローカルパスで、取得しない。開発中パッケージの参照に使う。
  • git source: それ以外。host/path@<tag> 形で @<tag> 必須
    • host/path を canonical source と呼ぶ (例 github.com/u/hikari-http)。
    • <tag> は git のタグ参照名としてそのまま使う (例 1.4.0 / v1.4.0 — リポジトリのタグ命名に合わせる)。バージョン範囲・semver 比較は行わない (exact)。

@<tag> を欠いた git source、解決不能な path dep は静的エラー (§6)。

2.2 どのマニフェストが効くか

import x := "pkg:<alias>" を含むファイル F の別名は、F から上方向に探索して最初に見つかるマニフェスト (package.toml) の deps で解決する。

  • entry プロジェクトはプロジェクト root にマニフェストを持つ。
  • 取得した依存は、キャッシュ内の自身の root にマニフェスト (配布物に同梱) を持つ。依存内部の pkg:その依存のマニフェストで解決する (推移依存)。
  • マニフェストが見つからないファイルからの pkg: import は静的エラー (§6)。単発スクリプトは pkg: を使えない。

別名がマニフェスト・ローカルなので、別々のパッケージが同じ別名 http を別バージョンに割り当てても干渉しない。

2.3 別名の字形

別名は [A-Za-z0-9_-]+ (英数字・_- の 1 文字以上) とする。これは TOML の bare key の字集合で、制約の理由は「[deps] テーブルのキーとしてそのまま書けること」に尽きる。. や空白を含む名前は拒む (hikari add--as <alias> を要求する)。TOML は quoted key ("a.b" = "...") でそれらを書けてしまうので、字形は host が読んだ時点で検査し、外れる別名は不正なマニフェスト (§6) として拒む。

別名は Hikari の識別子にはならないpkg:<alias> は文字列リテラルの中身であり、import が束縛する名前は利用側が別に決める。したがって - を含む別名も使え、識別子として書けない字形 (先頭が数字など) も差し支えない。

# package.toml
[deps]
hikari-http = "github.com/u/hikari-http@1.4.0"
import http := "pkg:hikari-http"  # 束縛名 http は利用側が決める

3. 解決と推移依存 (解決器なし・複数共存)

  1. 別名を効くマニフェストの deps で引き、取得元を得る。
  2. git source は lockfile (§4) で (canonical source, tag) → commit を確定し、キャッシュ (§5) の実体ディレクトリを得る。path dep はローカルパスをそのまま実体とする。
  3. 実体パッケージのマニフェストの entry を入口モジュールとして評価し、その値を返す (import が束縛する値)。
  4. 入口パッケージ内部の pkg: import は実体マニフェスト基準で再帰的に 1〜3 を繰り返す。

複数共存: キャッシュは (canonical source, version) をキーにする (commit は lockfile (§4) が固定する真実源で、キャッシュのキーには含めない)。同一パッケージでも別バージョンは別実体として共存し、互いに別オブジェクトになる。バージョンを 1 つに平らげる解決器・semver range は持たない。

トレードオフ (受容): 同一パッケージの複数バージョンがキャッシュに重複し、異バージョン間でインスタンス同一性は成立しない (別実体)。

4. lockfile (package.lock)

entry プロジェクト root に置く自動生成ファイル。hikari add / hikari update (hikari-command.md) が書き、全推移依存をフラットに記録する。再現ビルドの真実源。中身は TOML で、各レコードを array of tables ([[packages]]) で並べる。

# 自動生成。手で編集しない。
[[packages]]
source  = "github.com/u/hikari-http"
version = "1.4.0"
commit  = "a1b2c3d4e5f6..."
entry   = "src/main.hika"

[[packages]]
source  = "github.com/u/hikari-log"
version = "0.9.2"
commit  = "d4e5f6a7b8c9..."
entry   = "log.hika"
キー (各レコード) 意味
source canonical source (host/path@tag を除く)
version マニフェストで指定された tag
commit version を解決した時点の commit SHA (固定)
entry 実体マニフェストの入口 (再読み込みせず参照できるよう記録)

機械生成であり手編集しない。拡張子 .lock がそれを示し、冒頭コメントでも明示する (Cargo.lockpoetry.lock と同じ流儀で、中身が TOML でも lockfile は .lock を名乗る)。レコードは (source, version) 昇順で安定出力し、読み戻せる。

path dep は commit 固定を持たないため lockfile に記録せず、解決のたびにローカルツリーを直接参照する。

5. キャッシュ

  • 場所: 環境変数 HIKARI_CACHE。未設定時の既定は XDG に従い $XDG_CACHE_HOME/hikari (XDG_CACHE_HOME 未設定なら ~/.cache/hikari)。
  • キー (ディレクトリ): (canonical source, version) ($HIKARI_CACHE/<host>/<path>@<version>)。実体は lockfile (§4) が固定した commit をチェックアウトした読み取り専用ツリー。commit はキャッシュのディレクトリ名には含めず、lockfile を真実源とする。
  • hikari get (hikari-command.md) は lockfile / マニフェストを見てキャッシュへ復元する (CI・新規 clone 用)。lockfile があれば commit を信頼し、tag の再解決はしない。

6. 静的検査との関係 (static-analysis.md §1)

hikari check / hikari build / LSP 診断の前段検査は、pkg: について次を静的エラーとする (回復可能エラーにはしない):

  • マニフェスト不在: pkg: を使うファイルから上方にマニフェストが見つからない。
  • 未知の別名: <alias> が効くマニフェストの deps に無い。
  • 未取得: lockfile で解決済みだが実体がキャッシュに無い。取得 (hikari get) の実行を案内する。
  • 不正なマニフェスト: マニフェストが TOML として読めない / deps entry のスキーマ不一致 / 別名の字形違反 (§2.3) / @<tag> 欠落 / path dep 解決不能。「マニフェスト不在」とは別の診断である — 在るファイルを「見つからない」と言うと、どこが悪いのかを読者が引けない。

到達可能な pkg: 依存のソースも構文検査の対象に含める (キャッシュ内の .hika)。循環 import の扱いは相対 import と同じく実行時検出 (language-spec.md §13.4)。

エラーメッセージには未取得時の hikari get 案内などを載せるが、spec 章番号・バージョン等のメタ参照は埋め込まない。

7. hikari build (embed) との統合

hikari build (build.md) は package.toml がある場合 manifest dir を embed ルートとし、entry ツリー・package.tomlpackage.lock・依存グラフの .hika を 1 つの embed FS にまとめる。pkg: の解決は埋め込んだ manifest + lockfile + 名前空間レイアウトそのものが解決表となり、ランタイムは embed FS を (source, version) キャッシュとみなして解決する。

レイアウト:

  • git dep: lockfile で解決した全推移依存を pkg/<source>@<version>/... (= キャッシュと同じ (source, version) レイアウト) に配置する。
  • path dep: build 時点のローカルツリーを embed ルート相対の元位置に embed する。embed ルート外 (../...) を指す path dep は embed 不可としてエラーで停止する (git dep 化を案内)。commit 固定が無いため再現性はローカルツリー依存で、hikari build が stderr に警告する。
  • 各依存ディレクトリには package.toml を含め、依存内の pkg: も各自の manifest から解決できるようにする。
  • std: モジュールは従来どおり host コンパイル同梱 (embed FS とは独立、language-spec.md §13.4)。

8. CLI

依存の追加・取得・更新・削除は hikari コマンドが行う。構文と挙動は hikari-command.md:

コマンド 役割
hikari add <host/path@tag> [--as <alias>] マニフェスト deps 追記 + 取得 + lockfile 更新
hikari get マニフェスト / lockfile からキャッシュへ復元
hikari update [alias] tag を再解決して lockfile 更新
hikari remove <alias> マニフェスト deps から削除

9. 意図して入れないもの

以下は入れない。いずれも代わりの形がある:

  • semver range とバージョン自動解決器 (exact pin + 複数共存で代替)
  • 中央レジストリ・検索 (git 分散のみ)
  • HTTPS tarball / zip 直取得 (git のみ)
  • ファイル単位の pkg:<alias>/<path>.hika (パッケージ入口 1 点のみ)
  • パッケージの publish / yank / 署名・改ざん検証 (commit 固定のみ)
  • bare 名 import (リテラル限定の維持、language-spec.md §13.4)