-
Notifications
You must be signed in to change notification settings - Fork 4
crsearch.jsonフォーマット
crsearch.json のルートオブジェクトは Database 型である。
ℹ v1 のフォーマットが決まった経緯は、 cpprefjp/crsearch#1 を参照。
ℹ v2 以降の変更については、このドキュメントの変更履歴を参照。
ℹ v3 はこの行が挿入されたリビジョンから策定開始。v3の目的としては、大きな機能追加は入れない。v2の仕様をベースに、仕様として欠陥があるものや現実の実装都合における問題を仕様レベルで現状に合わせる。
サイト全体を示すオブジェクト。2つ以上含めてはならない。
Key | Type | Example | Description |
---|---|---|---|
base_url | String |
"https://cpprefjp.github.io" |
ベースURL(末尾スラッシュ無し) |
database_name | String |
"cpprefjp" |
crsearchデータベースの名前 |
namespaces | Array<Namespace> |
(必須) | サイトのトップレベルカテゴリ |
ids | Array<IndexID> |
(必須) | データベースで持つ全てのIndexID。この配列の頭から0-basedなインデックス(サロゲートキー、オートインクリメント)が振られる |
- ユニークである(サイトごとに1つしか存在しない)
-
crsearch.js を使っている検索プロバイダが
Database::database_name
によってタグ付けすることが期待できる
ℹ 現実的には、自分自身を容易に識別できないような不親切な名前をデータ内で使っている crsearch.json をわざわざ参照して使うようなことはしないだろう。そのため、信頼できるソースからの crsearch.json を読み込む際には、
Database::database_name
をそのままプログラム内で利用しても問題は起こらない。
サイトのトップレベルカテゴリを示すオブジェクト。
Key | Type | Example | Description |
---|---|---|---|
namespace | Array<String> |
["lang" ] |
グループ化のための名前(左結合) |
indexes | Array<Index> |
(必須) | インデックスデータ |
(optional) path_prefixes | Array<String> |
["lang" , "cpp14" ] |
Database::base_url に後続するパスプレフィックス(左結合)。省略した場合は namespace と同一になる。バージョニングの際の実際のURLとの対応付けが目的 |
(optional) cpp_version | String |
"14" |
対応するC++のバージョン。C++XXのXX部分 |
-
namespace
とcpp_version
が両方とも同じオブジェクトが、同一 Database オブジェクト内に複数存在してはならない。
ℹ 2つ以上の Namespace オブジェクトの
namespace
が同じ場合、それらは同一のカテゴリとして視覚的にまとめた上で、cpp_version
によってタグ付けをするべきである。
/
C++のトークンや、解説記事のタイトルなど、サイトで使われるあらゆる識別子を示すオブジェクト。
ℹ IndexID の目的は、同じトークンのグルーピングである。記事のユニーク性の保証は、
Index::page_id
を参照。
Key | Type | Example | Description |
---|---|---|---|
type | String |
(必須) | (後述) |
key | Array<String> |
["duration" , "operator+" ] |
type に応じたユニークインデックス(左結合) |
(optional) cpp_namespace | Array<String> |
["std" , "chrono" ] |
対象が存在するC++の名前空間。名前空間がある物でこれを省略した場合は、 ["std"] として扱う。 type が "namespace" の場合は、 cpp_namespace は暗黙のうちに key と同一として扱う |
- ユニーク性は無い。
ℹ C++言語の意味的に同名異義の識別子 についての解説ページが 別個 の記事として存在する場合は、 IndexID は重複させても良い。そのような場合は、
key
とcpp_namespace
が共に文字列レベルで完全一致しなければならない。これは、例えばオーバーロードやtemplateの特殊化などが相当する(実例は後述)。
⚠ 上記以外のケースで IndexID が重複した場合、検索結果やナビゲーションのUX上正しくグルーピングすることが不可能になるので、そのような曖昧さは非推奨である。
例:
-
std::operator==(basic_string, basic_string)
(std
名前空間内の関数) -
std::bitset::operator==(bitset)
(std::bitset
同士の等値比較用の、std::bitset
のメンバ関数)
この2つについて IndexID を考えた場合、crsearchの仕様では IndexID::key
が完全に同一なものになる。
-
IndexID::cpp_namespace
=["std"]
(これは省略可能だが、説明のため明示した) -
IndexID::key
=["operator=="]
("std::operator=="
ではない点に注意!)
上記のどちらの関数も、名前としては std::operator==
ではなく operator==
が自身を識別するために必要十分な表現であるので、 IndexID::key
は上記のようになる。
一方で、 std::basic_string
のための std::operator==
も、 std::bitset
同士のための std::bitset::operator==
も、どちらも名前空間は std::
である。
そのため、このままでは両者について IndexID::cpp_namespace
と IndexID::key
はどちらも完全に同一となり、この2つのデータだけでは区別が不可能となる。
ここでは、両者は type
で区別が可能である。
-
std::operator==(basic_string, basic_string)
-->IndexID::type
=function
-
std::bitset::operator==(bitset)
-->IndexID::type
=mem_fun
しかしながら、オーバーロード等では type
も同一になるため、ここにユニーク性を仮定してはならない。まとめたい場合は、視覚的にグルーピングするべきである。
IndexID が示す名前が同じでも、表示上の参照先(記事)が1つだけとは限らない。そのような場面としては、幾つかのケースが想定されている。この点は crsearch.json の仕様のバグではなく、想定範囲内である。
⚠ 以下の内容は全ての可能性を網羅していないので注意すること
- 完全に同一の対象を扱った解説記事でも、C++のバージョンごとにページが丸ごと分けられている場合
例:std::unexpected
はC++11で非推奨となり、C++17で削除された。これを説明するために、std::unexpected
に関するサイトの記事が2つ以上存在する可能性がある。 - 同一のclassについて、複数の側面から解説する記事が2つ以上ある場合
例:
(i) そのclassを含むヘッダファイルの解説記事
(ii) そのclass自体の解説記事
(iii) classが追加されたC++の言語規格のバージョンの仕様をまとめるページ - スタブ
例: スタブの都合上既存のエンティティを参照しているが、その対象の記事が既に存在しているなど
ℹ このような複数への参照を解決するためには、後述の
Index::related_to
を適切に設定する。
ℹ (実装依存の挙動) ユーザの検索でこれら同一の名前を持つ複数の存在が同時にマッチした場合は、単純に全てが表示される。その上で、ユーザが検索クエリを適切に絞り込むことでおおよそ想定通りに動く。これを簡単にするため、フロントエンドの実装はトークンをグルーピング化してもよい(便宜上、IndexIDを連想配列のキーなどにしてもよい)。
type |
何 |
---|---|
header | 標準ライブラリのヘッダ |
namespace | 対応するC++の物 |
class | 同上 |
function | 同上 |
mem_fun | 同上 |
enum | 同上 |
variable | 同上 |
type-alias | 標準規格における既存の型のエイリアス |
macro | マクロ、あるいはプリプロセッサの文脈で扱われるキーワード全て |
concept | 標準ライブラリのコンセプト |
article | サイトの記事 |
meta | サイトの記事をまとめるために使われるメタページや、サイト内の大きなカテゴリのトップページ |
どの type ? |
key における予約済み文字 |
---|---|
header |
" , < , > , / (サブディレクトリはsplitすること) |
namespace |
: |
class |
: |
function |
: |
mem_fun |
: |
enum |
: |
variable |
: |
type-alias |
: |
macro |
空白文字 |
concept |
: |
article |
改行文字 |
meta |
改行文字 |
サイトの記事や、記事をまとめるためのメタページを示すオブジェクト。
Key | Type | Example | Description |
---|---|---|---|
id | Integer |
(省略) | IndexIDのサロゲートキー |
page_id | Array<String> |
(v2から必須) | 絶対URLの自動生成で使われるページID。サービス内の全ページについてユニークなID(後述) |
related_to | Array<Integer> |
(意味的に存在する場合は必須。v2から必須) | IndexIDのサロゲートキーの配列。自分自身を「検索結果の関連」として表示する対象(後述) |
(optional) nojump | Boolean |
(省略) | クイックジャンプ先として表示してほしくない場合にtrueを指定する。執筆者向け資料ページや、スタブなどが対象 |
(optional) attributes | Array<String> |
["cpp14deprecated", "cpp17removed"] |
ページの属性情報。後述 |
- 全ての Index オブジェクトは、同じ Database オブジェクト内でグローバルにユニークでなければならない。
- 意味的なユニーク性は、
id
によってトークンレベルで保証される。 - 論理的なユニーク性は、
page_id
が Namespace レベルで保証する。
ℹ Index は Namespace レベルでユニークになり、 Namespace は Database レベルでユニークなので、 Index は常に Database レベルでもユニークとなる。
対象についての仕様追加や仕様変更が行われたC++の言語規格のバージョンを Index / IndexID のスコープで解決する方法は無い(後述のように、 crsearch.json は元々そのような論理構造を採用していないため、別の正しい解決方法がある)。
例として、 std::vector
を挙げる。
-
std::vector::push_back()
:メンバ関数、C++03以前から -
std::vector::emplace_back()
:メンバ関数、C++11以降から
C++11で追加された対象についての Index は、 Namespace::cpp_version
= "11"
な Namespace オブジェクトの子要素に含めればよい。このため、
std::vector
のメンバを扱うための Namespace オブジェクトは同じ crsearch.json 内に 少なくとも2つ以上 存在するはずである。
page_id
は、v2から必須となった。
内容には、本番環境のURLのパス構造を見た上で、ルート以下からファイルへの相対URLを パス区切り文字 /
で split した配列を格納する。その際、ファイル名の拡張子(つまり .md
)は削除する。
ℹ 元々、v1から既に存在していた 「IndexのURLを解決する処理」 は、本来は
IndexID::key
などを使って機械的に自動生成することが十分可能なものだった。一方で、現実的には記事自体をプログラム内で連想配列に格納する際のキーとして利用する場合など、実装上の様々な応用場面が浮上したことから v2 で必須となった。
crsearch は Index::page_id
に応じて絶対URLを自動生成して解決する。
// 擬似コード
let db = new CRS.Database
let ns = new CRS.Namespace
db.addNamespace(ns)
let idx = new CRS.Index
ns.addIndex(idx)
const url = new URL(
`${db.base_url}/${ns.path_prefixes.join('/')}/${idx.page_id.join('/')}.html`
)
related_to
は、v2から必須。
例として、 「あるメンバ関数 mem_fun
を cpprefjp の動的部分全てにおいて正しく認識する」 ためには、自身が所属する class
と header
の IndexID サロゲートキーがここに含まれている必要がある。
⚠ 実装のバグによってこの検出が失敗した場合には、その対象が名前空間スコープのフリー関数として表示(フォールバック)される可能性がある(ナビゲーションの問題なので、記事本体には影響しない)
ページの属性情報。
- cppXXdeprecated: C++バージョンXXで非推奨
- cppXXremoved: C++バージョンXXで削除
-
deprecated_in_latest
: 現行のC++バージョンで非推奨 -
removed_in_latest
: 現行のC++バージョンで削除
ℹ
*_in_latest
は互いに素であるため、どちらか片方しかつかない。
⚠
*_in_latest
系の属性は絶対に矛盾してはならない。
ℹ 上記の特別な属性がついていない場合は、全ての属性を集合レベルで加算して自動で解決されるので、つけなくてもよい。この最終的な属性の正しさに依存する細かい挙動は、実装中に数多く存在するので、特別な事情がある場合を除いては省略することが推奨される。