Add bilingual manual and localized docs routes

This commit is contained in:
2026-08-14 11:16:37 +09:00
parent 3645a2cc2d
commit cda32cc260
85 changed files with 2316 additions and 71 deletions
+193
View File
@@ -0,0 +1,193 @@
# Embedding
Decodal runtime は filesystem、network、environment variable を直接読み込まない。
ホストは global bindings と import の解決方法を注入し、評価結果を `Data` または application type として受け取る。
## Rust runtime
`Engine``ImportLoader` と global bindings を持つ。
外部 resource を必要としない source には `EmptyLoader` を使える。
```rust
use decodal::{EmptyLoader, Engine, Value};
let mut engine = Engine::new(EmptyLoader);
engine.bind_global(
"Service",
Value::object([
("name", Value::string_type()),
("port", Value::int_type().gt(443).default_int(8443)?),
("enabled", Value::bool_type().default_bool(true)?),
]),
)?;
let module = engine.add_root_source(
"service.dcdl",
"service.dcdl",
r#"{ name = "api"; port = 9443; } as Service"#,
)?;
let value = engine.eval_module(module)?;
let data = engine.materialize(&value)?;
```
`Value` は concrete value と host-defined range の両方を表す公開型である。
主な constructor は次の通りである。
- `Value::string``int``float``bool``array``object`: concrete value。
- `Value::string_type``int_type``float_type``bool_type`: primitive range。
- `Value::unknown`: 最上位 range `Unknown`
- `Value::array_of`: 全要素へ同じ range を適用する array range。
- `Value::map_of`: 全 field value へ同じ range を適用する associative-array range。
- `Value::object_with_rest`: named fields と残りの field range を持つ object。
## Typed Rust integration
`derive` feature の `Decodal` derive は、Rust struct から `DecodalSchema``DecodalDecode` を生成する。
```rust
use decodal::{Decodal, DecodalDecode, DecodalSchema};
#[derive(Decodal)]
struct Service {
name: String,
#[decodal(gt = 443, default = 8443)]
port: i64,
#[decodal(rename = "feature.enable", default = true)]
feature_enabled: bool,
}
```
`DecodalSchema::decodal_schema()``Engine::bind_global` に渡せる `Value` を返す。
materialize 済みの `Data``DecodalDecode::decodal_decode` で Rust type に変換できる。
追加 field を受け取る struct では、map field に `#[decodal(rest)]` を付ける。
```rust
use std::collections::BTreeMap;
use decodal::{Data, Decodal};
#[derive(Decodal)]
struct OpenConfig {
enabled: bool,
#[decodal(rest)]
extra: BTreeMap<String, Data>,
}
```
`BTreeMap<String, Data>``...Unknown``BTreeMap<String, String>``...String` に対応する。
named fields は rest map から除外される。
`#[decodal(rest)]` は struct ごとに1つだけ指定でき、`rename``default`、field constraints とは併用できない。
## Imports
`ImportLoader::load``LoadedImport::Source` または `LoadedImport::Value` を返す。
ホストは specifier の解決、filesystem や他の storage からの読み込み、content type の判定をすべて管理する。
`LoadedImport::Source` は DCDL source を返す。
`LoadedImport::Value` は Markdown、JSON、TOML などをホスト独自の規則で構造化して返す用途に使える。
```text
import "./post.md"
-> host reads and parses Markdown
-> LoadedImport::Value {
key: "content/post.md",
value: { frontmatter: {...}, body: "..." }
}
-> normal Decodal validation and materialization
```
stable `key` は import の同一性と diagnostic の provenance に使われる。
構造化した値が Decodal constraint に違反した場合、diagnostic は import key と logical value path、および違反した DCDL constraint の source span を示す。
外部形式そのものの parse error と位置情報は loader が報告する。
## Shared host environment
`HostEnvironment` は loader の作成と global binding の設定を1つにまとめる。
同じ environment を runtime、language service、LSP へ渡すことで、実行時と編集時の評価規則を一致させられる。
```rust
use decodal::{Engine, HostEnvironment};
struct AppEnvironment;
impl HostEnvironment for AppEnvironment {
type Loader = ContentLoader;
fn create_loader(&self) -> Self::Loader {
ContentLoader::new()
}
fn configure_engine(
&self,
engine: &mut Engine<Self::Loader>,
) -> decodal::Result<()> {
engine.bind_global("Site", site_schema())?;
Ok(())
}
}
```
transport 非依存の tooling は `decodal_language_service::LanguageService::new(&environment)` で構築する。
LSP integration では `decodal_lsp::LspEnvironment` を実装し、environment factory から server を起動する。
```rust
use decodal_lsp::{LspEnvironment, run_stdio};
impl LspEnvironment for AppEnvironment {}
run_stdio(|initialize| {
let _ = initialize;
Ok(AppEnvironment)
})?;
```
factory は server capability の応答前に client の `InitializeParams` を一度受け取る。
`LspEnvironment` の document lifecycle hooks を使うと、未保存の DCDL、Markdown、その他の resource を host-owned overlay に反映できる。
## JavaScript and browser environments
`decodal-wasm``DecodalLanguageService` は filesystem や仮想 project を仮定しない。
JavaScript 側が `globals``loadImport``completeImport` を提供する。
```js
import init, { DecodalLanguageService } from 'decodal-wasm';
await init();
const files = {
'schema.dcdl': 'Server = { port = Int; };',
};
const service = new DecodalLanguageService({
globals: {
App: {
enabled: { $decodal: 'Bool', default: true },
},
},
loadImport(_currentKey, specifier) {
const key = specifier.replace(/^\.\//, '');
return { kind: 'source', key, name: key, source: files[key] };
},
completeImport() {
return ['./schema.dcdl'];
},
});
const result = service.evaluate('main.dcdl', 'main.dcdl', 'App');
```
JavaScript の primitive、array、plain object は concrete value になる。
range は `$decodal` descriptor で指定する。
- `{ $decodal: 'String' | 'Int' | 'Float' | 'Bool' }`
- `{ $decodal: 'Unknown' }`
- `{ $decodal: 'Array', item }`
- `{ $decodal: 'Map', value }`
- `{ $decodal: 'Object', fields, rest }`
- `{ $decodal: 'Range', constraints, default }`
import callbacks は同期 API である。
network resource などの非同期入力は、評価の前に preload または cache しておく。