WorldCodex YAMLスキーマ定義
概要
本ドキュメントは、YAML文法の唯一のリファレンスである GameElementDefinition.md をもとにした、WorldCodex の
YAML ファイルの形式的なスキーマ定義(JSON Schema Draft 2020-12、
WorldCodex.schema.json)の保守方針をまとめたものです。個別の世界描写(ClimateSystem.md・RecipeSystem.md・
ContainerSystem.md・ActionSystem.md・TerrainGeneration.md・ExplorationSystem.md)の内容そのものは
スキーマの対象外で、それらが使う文法の妥当性のみを検証します。
スキーマの正はローダーの実装(src/loader/WorldCodexYamlLoader.ts と関連する parse*.ts モジュール群)です。本スキーマはローダーが
受け付ける文法の機械的な近似であり、乖離を見つけたらローダーに合わせてスキーマを直します。
1. 検証方法
npm test が毎回検証します(tests/world-codex/worldCodexSchema.test.ts。ajv の Draft 2020-12
バリデータを使う)。手で走らせて確かめるものではないので、乖離はその場で赤になります。
見るものを次のように分け、赤の意味が分かれるようにしています。
- スキーマ自体の妥当性: Draft 2020-12 として組めること。ajvのstrictモードを切っていないので、
綴りを間違えたキーワード(
additionalProprties)が黙って無視される事故もここで落ちます。 - 実データ全ファイルの受理:
src/assets/world-codex/以下の全YAMLファイルが、実際にゲームが ロードしているままの内容でスキーマを満たすこと(ローダーで読み込めるファイルはスキーマも通る、 が維持基準)。赤=スキーマがまだ知らない文法があるので、直すのはスキーマの側。 - 不正な記述の拒否: identifier の命名規則に反するキーを使う、未定義の比較演算子を使う、
set/addに未対応の対象キー(child)を使う、指す先のプロパティ名を決めない形でancestorを使う (destroy: ancestor)、枠のacceptにtagとobjectを同時指定する(またはどちらも省略する)、 trait の操作にtriggerを書き忘れる、廃止済みのauto_placementを使う、passivesを配列でなく単一マッピング で書く、conditionsの葉にslotとpropを同時指定する、conditionsのvalueに未対応のmax/minを使う、in/not_inに配列でないvalueを渡す、といった記述が拒否されること。 赤=スキーマが緩んで何も見なくなった。
受理だけを見ると、スキーマを緩めれば緑になってしまうので、拒否も併せて見ます。
2. スキーマの範囲
2.1 含めたもの
GameElementDefinition.md の3〜14節が定める文法全体(ルート構造・object_defs/traits・props・rangeイベント・
passives・conditions・active・pick・interactions・recipes・slots)。
例外は2.2節を参照。
2.2 対象だが中身を検証しないもの・ローダー未実装のもの
- 地形生成(
TerrainGeneration.md): ローダーは実装・ロード済み (parseGeneration.ts、terrain_generation.yaml)。本スキーマはparseGeneration.tsが読むルートキーを 許容するが中身は検証しない(trueスキーマ)。綴りの誤りはローダーが全部止めるので、それで 足ります——同梱の宣言のどのmappingへ未知キーを1つ足してもロードが落ちることをtests/world-codex/terrainGenerationUnknownKeys.test.tsが見ており、パーサへ新しい入れ子を足してrequireKnownKeysを置き忘れれば、その入れ子を使う宣言が入った時点で落ちます。 covers/layer(object_def直下)・unit(prop直下): 文法として文書化済みでスキーマにも 含めているが、ローダーは現時点でこれらのキーを解釈しない(読み飛ばす)。- 文脈依存の制約: 参照の起点(
conditionsのsubject・効果の対象キー)に何を書けるかは、その宣言が 置かれた場所が何を用意できるかで決まる(一覧はGameElementDefinition.md14.1節の表と同 11.5節 「役を書ける場所」)。この「どの文脈で書かれたか」に依存する制約は、スキーマでは表現せずローダーの ロード時チェックに委ねる(スキーマは全文脈の和集合を受理する)。 derived(導出値、同 16節・17節): 採否そのものが未決定のため含めていません。- YAML定義のマージ・上書き規則(同 3.3節・5節): 本スキーマは単一ファイルの構造のみを検証します。trait合成・ ファイル横断の整合性(参照先idの実在等)はロード時の検証に相当し、対象外です。
3. スキーマ化にあたって判断した細部(ドキュメント上は未確定・省略されていた点)
以下は、各ドキュメントの記述からは一意に決まらなかったものの、スキーマとして形にするために暫定的に判断した点です。 実装時に見直してください。
recipes.*.steps[].requires[].consumeは、既存サンプルが常に明示している(省略例が ない)ため、必須項目としました。countの省略時 デフォルト(RecipeSystem.md5節で未決定)はスキーマ上も任意項目のままにしています。- 枠(
slots.*.cells[]/slots.*.cell)のmaxは省略可で、省略すると無制限です。 interactions.*.triggerに書けるきっかけはsrc/domain/InteractionTrigger.tsが持ち、スキーマもそれに揃えます (ローダーも他の値をエラーにします)。 必須にしているのはtraits側だけで、object_defs側では省略できます——trait が配った同名の操作へ フィールド単位で重ねられる(GameElementDefinition.md5節)ので、conditionsだけを書いた形が正しく、 単独で立つ操作にtriggerが要ることは trait 合成の後でしか分かりません(2.2節)。- シンボル型プロパティかどうかは
valueの形(識別子形の文字列)でしか判別できないため、「シンボル型のstagesにminを書いたらエラー」「数値型のvalueにシンボルは書けない」といったプロパティ単位の整合はスキーマでは 検証できず、ロード時チェックに委ねています(2.2節の文脈依存制約と同じ扱い)。
4. 使い方
WorldCodex.schema.json は JSON Schema Draft 2020-12 準拠です。YAML ファイルをパースして得られるオブジェクトに対して、
一般的な JSON Schema バリデータ(Node.js の ajv 8、Python の jsonschema 等)でそのまま検証できます。同梱ぶんを
まとめて掛けるのは1節の試験なので、単体で走らせるならこれだけで足ります。
npx vitest run tests/world-codex/worldCodexSchema.test.ts
5. 未決事項・今後の検討課題
GameElementDefinition.md・ActionSystem.md・RecipeSystem.md・ContainerSystem.md側の未決事項 (各ドキュメントの該当節を参照)が確定するたびに、本スキーマも追随して更新する必要がある