Compare commits

10 Commits
Author SHA1 Message Date
Hare e4b9247c45 Extract CodeMirror language package 2026-07-09 03:49:44 +09:00
Hare 375bc80a57 Add package links to landing page 2026-07-09 03:31:20 +09:00
Hare 335ecde816 Fix JSR wasm package license 2026-07-09 03:29:27 +09:00
Hare 4142fcd46a Prepare 0.1.2 release 2026-07-09 03:12:09 +09:00
Hare 2d06dc3277 Add source link to header 2026-07-09 03:00:30 +09:00
Hare 37237dc1f7 Add source link to footer 2026-07-09 02:59:32 +09:00
Hare 2966d5b979 Add site footer 2026-07-09 02:58:53 +09:00
Hare ea858ad28e Remove landing page eyebrow 2026-07-09 02:57:55 +09:00
Hare 871d342e15 Add site landing page 2026-07-09 02:55:50 +09:00
Hare 6d80c66144 Trim open issues to materialization 2026-07-09 02:46:28 +09:00
46 changed files with 774 additions and 221 deletions
Generated
+4 -4
View File
@@ -25,7 +25,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "decodal"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"decodal-derive",
"regex",
@@ -33,14 +33,14 @@ dependencies = [
[[package]]
name = "decodal-cli"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"decodal",
]
[[package]]
name = "decodal-derive"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"decodal",
"proc-macro2",
@@ -50,7 +50,7 @@ dependencies = [
[[package]]
name = "decodal-wasm"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"decodal",
"serde_json",
+1 -1
View File
@@ -8,7 +8,7 @@ members = [
resolver = "2"
[workspace.package]
version = "0.1.1"
version = "0.1.2"
edition = "2024"
rust-version = "1.85"
license = "MIT OR Apache-2.0"
+1 -1
View File
@@ -20,4 +20,4 @@ default = []
regex = ["decodal/regex"]
[dependencies]
decodal = { version = "0.1.1", path = "../decodal-core" }
decodal = { version = "0.1.2", path = "../decodal-core" }
+1 -1
View File
@@ -15,7 +15,7 @@ publish = false
crate-type = ["cdylib", "rlib"]
[dependencies]
decodal = { version = "0.1.1", path = "../decodal-core" }
decodal = { version = "0.1.2", path = "../decodal-core" }
serde_json.workspace = true
wasm-bindgen.workspace = true
+6 -3
View File
@@ -45,11 +45,14 @@ Important paths:
```text
editors/lezer-decodal/decodal.grammar
site/decodal-site/src/lib/codemirror/decodal-parser.js
site/decodal-site/src/lib/codemirror/decodal-parser.terms.js
site/decodal-site/src/lib/codemirror/decodal.js
packages/decodal-codemirror/src/decodal.js
packages/decodal-codemirror/src/decodal-parser.js
packages/decodal-codemirror/src/decodal-parser.terms.js
```
The npm package is `decodal-codemirror`.
The JSR package is `@hare/decodal-codemirror`.
The Lezer grammar is derived from the canonical grammar documentation, but it is not a literal copy of the EBNF.
Precedence and token conflict handling are represented in the Lezer grammar in the form CodeMirror needs.
@@ -59,8 +59,9 @@ Config = MyConfig & {
## default の合成
初期方針では、`&` による異なる default 同士の合成は conflict とする。
同じ default は同一候補として扱ってよい
`&` で片方だけが default を持つ場合、その default を保持する。
同じ thunk 由来の default 同士は同一 default として保持する
異なる default 同士は conflict とする。
```text
merge_default(None, None) -> None
@@ -84,5 +84,5 @@ module root や field は thunk として保持され、参照されたときだ
関数引数は thunk として関数の environment に束縛する。
関数本体で引数が参照されたときだけ force する。
任意の関数呼び出し結果グローバルに memoize する必要はない。
関数呼び出し結果そのものはグローバルに memoize ない。
field に束縛された関数呼び出し結果は、その field thunk の評価結果として memoize される。
+56 -8
View File
@@ -23,25 +23,32 @@ cargo run -q -p decodal-cli --features regex -- examples/regex/main.dcdl
## crates.io release
The primary crates.io package is `decodal`, which contains the embeddable library.
`decodal-derive` provides optional derive macros for Rust struct integration.
Workspace support crates such as `decodal-cli` and `decodal-wasm` are not published for 0.1.0.
`decodal-derive` provides optional derive macros for Rust struct integration and is published only when the derive crate changes.
Workspace support crates such as `decodal-cli` and the Rust source crate `decodal-wasm` are not published to crates.io.
The generated WebAssembly package under `site/decodal-site/src/wasm/` is published to npm and JSR.
The project is dual licensed as `MIT OR Apache-2.0`.
```sh
cargo publish -p decodal-derive
cargo publish -p decodal
```
Publish `decodal-derive` first only when that crate has a new version:
```sh
cargo publish -p decodal-derive
```
Before publishing, run:
```sh
cargo fmt --check
cargo test
cargo check -p decodal --no-default-features
cargo publish -p decodal-derive --dry-run
cargo publish -p decodal --dry-run
```
If `decodal-derive` changed, also run `cargo publish -p decodal-derive --dry-run`.
## Web site and playground
The Astro documentation site and browser playground are kept in:
@@ -61,10 +68,10 @@ site/decodal-site/src/pages/playground.astro
site/decodal-site/src/scripts/playground.js
site/decodal-site/src/scripts/playground-examples.js
site/decodal-site/src/layouts/ManualLayout.astro
site/decodal-site/src/lib/codemirror/decodal.js
site/decodal-site/src/lib/codemirror/decodal-parser.js
site/decodal-site/src/lib/docs.js
site/decodal-site/src/lib/highlight.js
packages/decodal-codemirror/src/decodal.js
packages/decodal-codemirror/src/decodal-parser.js
crates/decodal-wasm/src/lib.rs
```
@@ -85,8 +92,49 @@ site/decodal-site/src/wasm/
These generated files are committed so the site can be built without requiring every consumer to regenerate the wasm package first.
The playground editor uses CodeMirror 6 with the generated Lezer parser in `src/lib/codemirror/decodal-parser.js`.
Publish the generated WebAssembly package from its package directory:
```sh
cd site/decodal-site/src/wasm
npm publish
npx jsr publish
```
Run dry-runs first when preparing a release:
```sh
npm pack --dry-run
npx jsr publish --dry-run
```
The npm package name is `decodal-wasm`.
The JSR package name is `@hare/decodal-wasm`.
JSR currently expects a single SPDX license identifier in `jsr.json`; the WebAssembly package metadata uses `MIT` while the Rust workspace remains dual licensed as `MIT OR Apache-2.0`.
The playground editor uses the `decodal-codemirror` package with the generated Lezer parser in `packages/decodal-codemirror/src/decodal-parser.js`.
The canonical grammar is documented in `doc/manual/souce/language/grammar.md`; regenerate the Lezer parser when that grammar or `editors/lezer-decodal/decodal.grammar` changes.
Publish the CodeMirror package from its package directory:
```sh
cd packages/decodal-codemirror
npm install
npm publish
npx jsr publish
```
Run dry-runs first when preparing a release:
```sh
npm install
npm pack --dry-run
npx jsr publish --dry-run
```
The npm package name is `decodal-codemirror`.
The JSR package name is `@hare/decodal-codemirror`.
JSR currently expects a single SPDX license identifier in `jsr.json`; the CodeMirror package metadata uses `MIT` while the Rust workspace remains dual licensed as `MIT OR Apache-2.0`.
The documentation build still uses the lightweight JavaScript fallback highlighter so Astro can render Markdown without initializing WASM at build time.
To run the site locally:
@@ -168,7 +216,7 @@ When the Decodal syntax changes:
```sh
cd site/decodal-site
npx lezer-generator ../../editors/lezer-decodal/decodal.grammar -o src/lib/codemirror/decodal-parser.js
npx lezer-generator ../../editors/lezer-decodal/decodal.grammar -o ../../packages/decodal-codemirror/src/decodal-parser.js
```
5. Add or update corpus/tests/examples.
@@ -188,11 +188,12 @@ RuntimeValue =
## default の合成
同じフィールドに複数の `default` 合成された場合の詳細規則は未確定である。
現時点の単純な方針は以下である。
`default` 合成規則は以下である。
- `&` による default 同士の衝突はエラーにする。
- 同一 default 値は許可してよい
- `//` による patch では右辺 default が左辺 default を置き換える。
- `&` で片方だけが default を持つ場合、その default を保持する。
- `&` で両方が異なる default を持つ場合、conflict になる
- `Abstract & Concrete` が成功した場合、結果は concrete value になり default は消える。
- `//` では右辺が左辺を置き換える。object/object の場合は field ごとに再帰 patch されるため、右辺 field の default が左辺 field の default を置き換える。
この方針により、`&` は制約を保った合成、`//` は上書き操作として説明できる。
`default` thunk は materialize 時に必要になった時点で評価する。
評価された default value は、同じ abstract value に残っている制約を満たす必要がある。
+1 -1
View File
@@ -74,5 +74,5 @@ Error 評価失敗
関数引数は thunk として渡せる。
関数本体内で引数が参照されたときに評価する。
任意の関数呼び出し結果グローバルに memoize することは必須ではない。
関数呼び出し結果そのものはグローバルに memoize ない。
ただし、フィールドに束縛された呼び出し結果は、そのフィールド thunk の評価結果として memoize される。
+15 -25
View File
@@ -5,21 +5,19 @@
## 基本的な設定スキーマ
```dcdl
rec {
Host = IPv4Address;
Host = IPv4Address;
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
MyConfig = {
host = Host;
port = NarrowedPort default 8080;
feature_hoge = {
enable = Bool default true;
fuga = Int default 10;
};
MyConfig = {
host = Host;
port = NarrowedPort default 8080;
feature_hoge = {
enable = Bool default true;
fuga = Int default 10;
};
}
};
NewConfig = MyConfig & {
host = "127.0.0.1";
@@ -33,28 +31,20 @@ disabled_config = NewConfig & {
enabled_config = NewConfig;
```
## 関数と文字列生成
## 関数と制約
```dcdl
let
maybe_hw = String & /Hello! .*/;
part = {
greet = String;
target = String;
};
mk_hw = (part: part) =>
maybe_hw & "${part.greet}! ${part.target}";
Port = Int & >= 1 & <= 65535;
add_offset = (base: Port, offset: Int) => base + offset;
in
mk_hw({
greet = "Hello";
target = "World";
})
add_offset(8000, 80)
```
評価結果:
```text
"Hello! World"
8080
```
## match
@@ -3,10 +3,7 @@
function call expression は、関数値を引数に適用する式である。
```dcdl
mk_hw({
greet = "Hello";
target = "World";
})
increment(41)
```
## 評価
@@ -14,4 +11,5 @@ mk_hw({
引数は thunk として渡せる。
関数本体内で引数が参照されたときに評価する。
任意の関数呼び出し結果グローバルに memoize することは必須ではない。
関数呼び出し結果そのものはグローバルに memoize ない。
フィールドに束縛された呼び出し結果は、そのフィールド thunk の評価結果として memoize される。
@@ -3,11 +3,7 @@
function expression は、引数を受け取り式を返す値である。
```dcdl
(part: {
greet = String;
target = String;
}) =>
"${part.greet}! ${part.target}"
(value: Int) => value + 1
```
関数仕様の詳細は [関数](../functions.md) に置く。
+3 -5
View File
@@ -4,12 +4,10 @@ let expression は、ローカル束縛を作る。
```dcdl
let
part = {
greet = "Hello";
target = "World";
};
base = 8000;
offset = 80;
in
"${part.greet}! ${part.target}"
base + offset
```
## 評価
@@ -12,4 +12,5 @@ config.feature_hoge.enable
左側の式を object として評価し、指定された field を参照する。
参照先 field は必要になるまで評価されない。
存在しない field への参照をエラーにするか、open schema として扱うかは未確定である。
存在しない field への参照は diagnostic になる。
Decodal は unknown / Any のような値を伝播せず、field の有無を曖昧にしない。
@@ -1,12 +1,8 @@
# String Interpolation Expression
# String Interpolation
string interpolation は、文字列内に式を埋め込む候補機能である
文字列補間は初期実装には含めない
```dcdl
"${part.greet}! ${part.target}"
```
Decodal の string literal は、現時点では literal text として扱う。
式を埋め込む構文は定義しない。
## 評価
補間式の評価タイミングは通常の遅延評価に従う。
文字列補間を初期実装に含めるかは未確定である。
必要になった場合は、文字列連結や明示的な formatting function として別途設計する。
+19 -52
View File
@@ -5,54 +5,47 @@
## 構文
```dcdl
(part: {
greet = String;
target = String;
}) =>
"${part.greet}! ${part.target}"
(value: Int) => value + 1
```
関数呼び出しは通常の呼び出し構文で行う。
```dcdl
mk_hw({
greet = "Hello";
target = "World";
})
let
increment = (value: Int) => value + 1;
in
increment(41)
```
複数引数の構文は候補として以下を想定する。
複数引数も指定できる。
```dcdl
(
input_a: {
hoge = Int & >= 0;
},
input_b: {
fuga = 20;
}
) =>
(input_a: { hoge = Int & >= 0; }, input_b: { fuga = Int; }) =>
{
# ...
hoge = input_a.hoge;
fuga = input_b.fuga;
}
```
## 関数の意味
関数は値として扱える
ただし、最終データとして関数値を出力できるかどうかは別途定める。
設定ファイルを materialize する段階では、未適用の関数値は出力不能な値として扱うのが自然である。
関数は runtime value として扱えるが、最終データとして materialize することはできない
未適用の関数値が materialize 対象に残っている場合は diagnostic になる。
関数値は opaque であり、関数値同士の等価性は提供しない。
`&` で関数値同士を合成すると conflict になる。
## 評価方針
関数は以下の方針を基本とする。
関数は以下の方針で評価する。
- 関数は純粋である。
- 関数はレキシカルスコープを持つ。
- 関数は定義時の環境を参照として保持する。
- 引数は必要になるまで評価ない。
- フィールドに束縛された関数呼び出し結果は、そのフィールド評価結果として memoize される
- 任意の関数呼び出しそのものをグローバルに memoize することは必須ではない
- 引数は thunk として渡され、必要になるまで評価されない。
- 関数呼び出し結果そのものはグローバルには memoize しない
- フィールドに束縛された関数呼び出し結果は、そのフィールド thunk の評価結果として memoize される
- 再帰的な依存は thunk cycle として diagnostic になる。
関数値の内部モデル例:
@@ -63,29 +56,3 @@ Function {
env: EnvRef
}
```
## 関数と重さ
関数の文法・パーサー自体は大きくない。
実装上の重さは、主に評価モデルと意味論から発生する。
注意点:
- クロージャが環境を掴む。
- 引数を lazy にするか strict にするかを決める必要がある。
- 関数呼び出し結果をどこまで memoize するかを決める必要がある。
- 再帰関数を許可するかを決める必要がある。
- 関数値同士の `&` をどう扱うかを決める必要がある。
- 関数値を object に入れたとき、materialize 可能かを決める必要がある。
- import 循環と関数適用が絡んだときの cycle detection が必要になる。
軽量に保つため、初期仕様では以下の制限を検討できる。
- 関数は pure。
- lexical closure は許可。
- 引数は thunk として渡す。
- 関数本体は必要になるまで評価しない。
- 関数値は opaque。
- 関数同士の `&` は、同一関数参照以外は conflict。
- 関数値は最終データとして出力できない。
- 再帰は cycle error として扱う、または v1 では禁止する。
@@ -95,4 +95,5 @@ match value {
通常の式はエラー内容に基づいて分岐できない。
汎用 `try / catch` は core には含めない。
fallback は `default``match`、および将来的な optional import / optional field access のような限定された仕組みで表現する。
fallback は `default``match` で表現する。
optional import や optional field access は core には含めない。
@@ -29,7 +29,8 @@ result = schema;
```
この場合、`result` の右辺の `schema` は同じ module の top-level field `schema` を参照する。
通常の object literal 内の field を暗黙に recursive scope にするかは別仕様とする
通常の object literal 内の field は、その object 内の sibling field を暗黙には識別子として参照できない
object 内の値を参照する場合は、外側で束縛された値や明示的な path reference を使う。
## SourceLoader
+3 -12
View File
@@ -183,19 +183,10 @@ Patched = Base // {
## object 全体の置換
`//` が deep patch である場合、object 全体を置き換えたいときの escape hatch が必要になる。
`//` では object/object は常に deep patch される。
object field 全体を特別に置き換えるための `replace(...)` 構文や組み込み関数は core には含めない。
候補として、`replace(...)` を組み込み関数として提供する
```dcdl
Replaced = Base // {
feature_hoge = replace({
enable = false;
});
};
```
この場合、`feature_hoge` は再帰 patch されず、右辺の object に丸ごと置き換わる。
object 全体を別構造にしたい場合は、patch 対象より外側で値を作り直す
## `&` と `//` の使い分け
+3 -6
View File
@@ -1,7 +1,7 @@
# 構文と字句
この章では、表層構文の方針をまとめる。
厳密な EBNF は未確定であり、今後このファイルに詳細化する。
厳密な構文は [Grammar](./grammar.md) の EBNF を参照する。
## 言語名と拡張子
@@ -93,9 +93,9 @@ config.feature_hoge.enable
}
```
## 予約語候補
## 予約語
以下は予約語または予約構文として扱う候補である
以下は予約語として扱う
```text
let
@@ -105,11 +105,8 @@ import
default
true
false
rec
```
`rec` の扱いは未確定である。
## 演算子
主要な演算子は以下である。
+6 -3
View File
@@ -9,7 +9,10 @@ ratio = Float;
threshold = Float default 0.5;
```
## 未確定事項
## Int との関係
`Int``Float` の暗黙変換を許可するかは未確定である。
軽量実装では、両者を明確に分ける方が単純である。
`Int``Float` は primitive type constraint としては別の型である。
`Float` constraint は concrete `Float` を要求し、`Int` constraint は concrete `Int` を要求する。
数値演算や比較式では `Int``Float` を同じ numeric value として扱える。
混在した四則演算の結果は `Float` になる。
+2 -1
View File
@@ -17,4 +17,5 @@ greeting = String default "hello";
message = String & /Hello! .*/;
```
正規表現制約を必須機能にするかは未確定である。
正規表現制約の検証は Rust crate の `regex` feature で有効化される。
feature が無効な場合、正規表現制約は具体 string に対して検証できず diagnostic になる。
+14 -51
View File
@@ -1,60 +1,23 @@
# 未確定事項
今後決める必要がある事項を管理する。
詳細化するときは、各項目を該当する仕様ファイルへ移動または反映する
実装または仕様方針が固まった項目は、該当する仕様ファイルへ反映してここから外す
## 構文
## Materialize target and host projection
- 正式な字句・構文仕様
- 演算子の優先順位
- `rec` の扱い。
- コメント構文を `#` のみにするか。
Decodal の評価結果は、制約・default・関数値を含む中間値になり得る
そのため、Decodal 単独で常に「最終成果物」を一意に決めるのではなく、host 側が期待する型や出力形式を与えて materialize / decode する経路を明確にする必要がある
## 型・制約
決めること:
- 配列要素の制約表現
- object の open/closed schema の扱い
- 正規表現を必須機能にするか optional feature にするか。
- 代表的な組み込み述語の範囲
- Rust API で評価結果の field/path を選択して decode / materialize できるようにするか
- `decodal-derive` の struct schema と評価結果を合成して decode する経路を、主要な materialize path として位置づけるか
- CLI / WASM では target path を指定して JSON-compatible value へ materialize する形にするか。
- 制約や関数値が残った値を出力したい場合、materialize ではなく inspect/debug API として分けるか
## default
現時点の案:
- `default` 同士の conflict 解決規則
- `&` による default 合成の厳密な規則
- `//` による default 置換の厳密な規則
- default thunk の評価失敗をどの段階で報告するか
## 演算子
- `//` による制約・default の置換詳細。
- `replace(...)` を採用するか、別構文を設けるか。
- 配列に対する patch 操作を右辺置換だけにするか。
- 配列 append / prepend / remove などを提供するか。
## 関数
- 関数値の最終出力可否。
- 再帰関数を許可するか。
- 関数同士の `&` の扱い。
- 関数値の等価性。
- 関数呼び出し結果の memoize 範囲。
## 評価
- thunk のエラー memoize 方針。
- import cache の単位。
- 循環 import の診断メッセージ。
- materialize 対象の範囲指定方法。
## match
- match の網羅性チェックを行うか。
- 到達不能分岐を警告するか。
- パターン構文の範囲。
## エラー処理
- optional import を導入するか。
- optional field access を導入するか。
- optional fallback が捕捉できる失敗の範囲。
- エラー報告に制約由来の説明をどこまで含めるか。
- Rust では `evaluate -> select field/path -> expected schema と合成 -> decode` を主経路にする
- CLI / WASM では、明示された target path または module 全体を JSON-compatible value として materialize する
- materialize できない unresolved abstract value、default のない制約値、関数値は diagnostic にする
- Decodal 言語内には materialize 構文を追加せず、host API / CLI / WASM の責務として扱う
+2 -2
View File
@@ -12,7 +12,7 @@ Regenerate the CodeMirror parser from the site directory:
```sh
cd ../../site/decodal-site
npx lezer-generator ../../editors/lezer-decodal/decodal.grammar -o src/lib/codemirror/decodal-parser.js
npx lezer-generator ../../editors/lezer-decodal/decodal.grammar -o ../../packages/decodal-codemirror/src/decodal-parser.js
```
The generated parser is committed with the site because the playground imports it directly.
The generated parser is committed with the `decodal-codemirror` package because both the playground and external Web editors consume it.
+54
View File
@@ -0,0 +1,54 @@
# decodal-codemirror
CodeMirror 6 language support for Decodal.
This package provides the Lezer parser metadata, highlighting tags, indentation rules, and block folding used by the Decodal Web playground.
It does not include the Decodal runtime or WebAssembly evaluator.
Use `decodal-wasm` when you want to evaluate Decodal in a browser.
## Install
```sh
npm install decodal-codemirror
```
JSR:
```sh
deno add jsr:@hare/decodal-codemirror
```
## Usage
```js
import { basicSetup } from 'codemirror';
import { EditorView } from '@codemirror/view';
import { decodal } from 'decodal-codemirror';
new EditorView({
doc: 'Server = { port = Int default 8080; };',
extensions: [
basicSetup,
decodal(),
],
parent: document.querySelector('#editor'),
});
```
## Exports
```js
import {
decodal,
decodalLanguage,
decodalHighlightStyle,
} from 'decodal-codemirror';
```
`decodal()` accepts a small options object:
```js
decodal({ highlight: false })
```
Use this when you want the language support without the bundled highlight style.
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@hare/decodal-codemirror",
"version": "0.1.2",
"license": "MIT",
"exports": "./src/mod.ts",
"imports": {
"@codemirror/language": "npm:@codemirror/language@^6.12.4",
"@lezer/highlight": "npm:@lezer/highlight@^1.2.3",
"@lezer/lr": "npm:@lezer/lr@^1.4.10"
},
"publish": {
"include": [
"README.md",
"src/mod.ts",
"src/decodal.js",
"src/decodal.d.ts",
"src/decodal.js.d.ts",
"src/decodal-parser-jsr.js",
"src/decodal-parser.js",
"src/decodal-parser.terms.js",
"package.json"
]
}
}
+101
View File
@@ -0,0 +1,101 @@
{
"name": "decodal-codemirror",
"version": "0.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "decodal-codemirror",
"version": "0.1.2",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@codemirror/language": "^6.12.4",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10"
}
},
"node_modules/@codemirror/language": {
"version": "6.12.4",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.4.tgz",
"integrity": "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.23.0",
"@lezer/common": "^1.5.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/state": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.1.tgz",
"integrity": "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==",
"license": "MIT",
"dependencies": {
"@marijn/find-cluster-break": "^1.0.0"
}
},
"node_modules/@codemirror/view": {
"version": "6.43.6",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.6.tgz",
"integrity": "sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.7.0",
"crelt": "^1.0.6",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@lezer/common": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz",
"integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==",
"license": "MIT"
},
"node_modules/@lezer/highlight": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.3.0"
}
},
"node_modules/@lezer/lr": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz",
"integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@marijn/find-cluster-break": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz",
"integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==",
"license": "MIT"
},
"node_modules/crelt": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz",
"integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==",
"license": "MIT"
},
"node_modules/style-mod": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
"license": "MIT"
},
"node_modules/w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
"license": "MIT"
}
}
}
+35
View File
@@ -0,0 +1,35 @@
{
"name": "decodal-codemirror",
"version": "0.1.2",
"description": "CodeMirror 6 language support for Decodal.",
"type": "module",
"license": "MIT OR Apache-2.0",
"repository": {
"type": "git",
"url": "git+https://gitea.hareworks.net/Hare/Decodal.git",
"directory": "packages/decodal-codemirror"
},
"exports": {
".": {
"types": "./src/decodal.d.ts",
"import": "./src/decodal.js"
},
"./parser": "./src/decodal-parser.js",
"./terms": "./src/decodal-parser.terms.js"
},
"types": "./src/decodal.d.ts",
"files": [
"README.md",
"src/"
],
"keywords": [
"decodal",
"codemirror",
"lezer"
],
"dependencies": {
"@codemirror/language": "^6.12.4",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10"
}
}
@@ -0,0 +1,16 @@
// This file was generated by lezer-generator. You probably shouldn't edit it.
import {LRParser} from "npm:@lezer/lr@^1.4.10"
export const parser = LRParser.deserialize({
version: 14,
states: "7vQYQPOOO#nQPO'#CaOOQO'#Cr'#CrO$wQPO'#CyO&UQPO'#DOO&^QPO'#DSO&eQPO'#DWO&mQPO'#CqO$wQPO'#DcO&wQPO'#DhOOQO'#Cq'#CqOOQO'#Cp'#CpO&|QPO'#CoO$wQPO'#CoOOQO'#Cn'#CnO)fQPO'#CmO.XQPO'#ClO0]QPO'#CkOOQO'#Cj'#CjO2TQPO'#CiO3xQPO'#ChO5jQPO'#CgO7UQPO'#CfOOQO'#Ce'#CeO7`QPO'#C`O7eQPO'#C_OOQO'#Dz'#DzQYQPOOO8xQPO'#D{O8}QPO,58{OOQO,59e,59eO9VQPO'#CaOOQO,59j,59jO9_QPO,59jOOQO,59n,59nO9gQPO,59nO9oQPO'#EOO9tQPO'#DYO9|QPO,59rO:RQPO'#CqO:`QPO'#D^O:hQQO,59vO:mQPO,59vO:rQPO,59]O:wQPO,59}OOQO,5:S,5:SO:|QPO'#DjOOQO,59[,59[O;TQPO,59[OOQO,59Z,59ZO$wQPO,59YO$wQPO,59XO$wQPO,59WOOQO'#Dr'#DrO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zOOQO,58y,58yOOQO-E7x-E7xOOQO,5:g,5:gOOQO-E7y-E7yO;YQPO1G/UO;bQPO1G/UOOQO1G/U1G/UO;jQPO1G/YO;qQPO1G/YOOQO1G/Y1G/YOOQO,5:j,5:jOOQO-E7|-E7|O$wQPO1G/^O$wQPO,59yO;yQPO,59xO<RQPO,59xO$wQPO1G/bO<ZQQO1G/bOOQO1G.w1G.wO<`QPO1G/iO<jQPO'#DkOOQO,5:U,5:UO<rQPO,5:UOOQO1G.v1G.vOOQO1G.t1G.tO<wQPO1G.sO@_QPO1G.rOAyQPO1G.qOOQO1G.p1G.pOCqQPO1G.oOEfQPO1G.nOFxQPO1G.mOOQO1G.l1G.lOOQO1G.f1G.fOOQO1G.s1G.sOOQO1G.r1G.rOOQO1G.q1G.qOOQO1G.o1G.oOOQO1G.n1G.nOOQO1G.m1G.mOOQO,5:h,5:hOOQO7+$p7+$pOHfQPO7+$pOOQO-E7z-E7zOOQO,5:i,5:iOOQO7+$t7+$tOHnQPO7+$tOOQO-E7{-E7{OOQO7+$x7+$xOOQO1G/e1G/eOHuQPO'#D_OOQO,5:k,5:kOHzQPO1G/dOOQO-E7}-E7}OOQO7+$|7+$|O$wQPO7+$|OOQO'#Df'#DfOISQPO'#DeOOQO7+%T7+%TOIXQPO7+%TOIaQPO,5:VOIhQPO,5:VOOQO1G/p1G/pOOQO<<H[<<H[PIpQPO'#D|OOQO<<H`<<H`P$wQPO'#D}PIuQPO'#EPOOQO<<Hh<<HhO$wQPO,5:POIzQPO<<HoOJUQPO<<HoOOQO<<Ho<<HoOJ^QPO1G/qOOQO1G/k1G/kOOQO,5:l,5:lOOQOAN>ZAN>ZOJeQPOAN>ZOOQO-E8O-E8OOOQOG23uG23uP<cQPO'#EQO$wQPO,59XO$wQPO,59WO$wQPO,59VO$wQPO,59TO$wQPO,59SO$wQPO,59ROJoQPO1G.rOKVQPO'#ClOKjQPO'#CkOL^QPO'#ChOM^QPO'#CgONaQPO'#CfO$wQPO,59WO$wQPO,59UO$wQPO,59QO! jQPO1G.qO!!QQPO'#CkO!#_QPO'#CiO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zO!$[QPO1G.oO!$rQPO1G.nO!%YQPO1G.mO!%zQPO'#CiO!&rQPO'#ChO!'gQPO'#CgO!(XQPO'#CfO!(vQPO'#C`",
stateData: "!)Y~O!wOSPOS~OUPOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO{UO!PVO!WWO!]XO!`]O!a]O~OneXoeXpeXqeX!PeX!aeX!beX!ceX!deX!eeX!geX!heX!ieX!jeX!keX!leX!meX~OVlOUeXWTXgeXheXieXjeXkeXleXseXteXweX{eX!WeX!]eX!`eX!ueX~P!gOUYOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO{UO!PVO!WWO!]XO!`]O!a]O~OUoOupO~OyrO~P$wOUoO}|P~OUwO!TyO~P]Og}O~OV!QO!P!OOUcXgcXhcXicXjcXkcXlcXncXocXpcXqcXscXtcXwcX{cX!WcX!]cX!`cX!acX!bcX!ccX!dcX!ecX!gcX!hcX!icX!jcX!kcX!lcX!mcX!ucXxcXycX!TcXucX!ScX~O!b!SO!c!SOUaXgaXhaXiaXjaXkaXlaXnaXoaXpaXqaXsaXtaXwaX{aX!PaX!WaX!]aX!`aX!aaX!daX!eaX!gaX!haX!iaX!jaX!kaX!laX!maX!uaXVaXxaXyaX!TaXuaX!SaX~OU`Xg`Xh`Xi`Xj`Xk`Xl`Xn`Xo`Xp`Xq`Xs`Xt`Xw`X{`X!P`X!W`X!]`X!``X!e`X!g`X!h`X!i`X!j`X!k`X!l`X!m`X!u`Xx`Xy`X!T`Xu`X!S`X~O!a!TO!d!TO~P,OOn!VOo!VOp!VOq!VO!g!VO!h!VOU_Xg_Xh_Xi_Xj_Xk_Xl_Xs_Xt_Xw_X{_X!P_X!W_X!]_X!`_X!a_X!i_X!j_X!k_X!l_X!m_X!u_X~O!e!UO~P.cOU]Xg]Xh]Xi]Xj]Xk]Xl]Xn]Xo]Xp]Xq]Xs]Xt]Xw]X{]X!P]X!W]X!]]X!`]X!a]X!j]X!k]X!l]X!m]X!u]X~O!i!XO~P0dOU[Xg[Xh[Xi[Xj[Xk[Xl[Xn[Xo[Xp[Xq[Xs[Xt[Xw[X{[X!P[X!W[X!][X!`[X!a[X!k[X!l[X!m[X!u[X~O!j!YO~P2[OUZXgZXhZXiZXjZXkZXlZXnZXoZXpZXqZXsZXtZXwZX{ZX!PZX!WZX!]ZX!`ZX!aZX!lZX!mZX!uZX~O!k!ZO~P4POUYXgYXhYXiYXjYXkYXlYXnYXoYXpYXqYXsYXtYXwYX{YX!PYX!WYX!]YX!`YX!aYX!uYX~O!l![O!m!]O~P5qOW!^O~Ot!_OURXgRXhRXiRXjRXkRXlRXnRXoRXpRXqRXsRXwRX{RX!PRX!WRX!]RX!`RX!aRX!uRX~OU!aO~OVlOWTa~OVlOWTX~Ot!cOu!eO~Ox!fOy!hO~Ot!iO~OUoO}|X~O}!kO~O!S!lOVeX!TeX~P!gOx!mO!T!QX~O!U!oO~O!T!pO~O!T!qO~Os!rO~O!T!tO~P$wOU!vO~OUoOu#YO~Ot#ZOu#YO~Oy#^O~P$wOx#_Oy#^O~OU#cO!T!Qa~Ox#eO!T!Qa~O!U#hO~Ou#kO!Z#iO~P$wOx#mO!T!_X~O!T#oO~O!b!SO!c!SOUaigaihaiiaijaikailainaioaipaiqaisaitaiwai{ai!Pai!Wai!]ai!`ai!aai!dai!eai!gai!hai!iai!jai!kai!lai!mai!uaixaiyai!Taiuai!Sai~O!d!TOn`io`ip`iq`is`it`i!e`i!g`i!h`i!i`i!j`i!k`i!l`i!m`i~OU`ig`ih`ii`ij`ik`il`iw`i{`i!P`i!W`i!]`i!``i!a`i!u`i~P?^Os_it_i!i_i!j_i!k_i!l_i!m_i~O!e!UOU_ig_ih_ii_ij_ik_il_in_io_ip_iq_iw_i{_i!P_i!W_i!]_i!`_i!a_i!u_i~PAbOs]it]i!j]i!k]i!l]i!m]i~O!i!XOU]ig]ih]ii]ij]ik]il]in]io]ip]iq]iw]i{]i!P]i!W]i!]]i!`]i!a]i!u]i~PC]Os[it[i!k[i!l[i!m[i~O!j!YOU[ig[ih[ii[ij[ik[il[in[io[ip[iq[iw[i{[i!P[i!W[i!][i!`[i!a[i!u[i~PETO!k!ZOUZigZihZiiZijZikZilZinZioZipZiqZisZitZiwZi{Zi!PZi!WZi!]Zi!`Zi!aZi!lZi!mZi!uZi~OUoOu#pO~Oy#rO~P$wO!S!lO~OU#cO!T!Qi~O!S#vO~Ot#wOu#yO~O!T!_a~P$wOx#zO!T!_a~OUoO~OU#cO~Ou#}O!Z#iO~P$wOt$OOu#}O~O!T!_i~P$wOu$QO!Z#iO~P$wO!a!TOx`iy`i!T`iu`i!S`i~P?^O!a$SO!d$SOV`X!b`X!c`X~P,OO!e$TOV_X!b_X!c_X!d_Xx_Xy_X!T_Xu_X!S_X~P.cO!j$VOV[X!b[X!c[X!d[X!e[X!g[X!h[X!i[Xx[Xy[X!T[Xu[X!S[X~P2[O!k$WOVZX!bZX!cZX!dZX!eZX!gZX!hZX!iZX!jZXxZXyZX!TZXuZX!SZX~P4PO!l$XO!m$bOVYX!bYX!cYX!dYX!eYX!gYX!hYX!iYX!jYX!kYXxYXyYX!TYXuYX!SYX~P5qO!e$`Ox_iy_i!T_iu_i!S_i~PAbOn!VOo!VOp!VOq!VO!e$`O!g!VO!h!VOx_Xy_X!i_X!j_X!k_X!l_X!m_X!T_Xs_Xt_Xu_X!S_X~O!i$aOV]X!b]X!c]X!d]X!e]X!g]X!h]Xx]Xy]X!T]Xu]X!S]X~P0dO!i$gOx]iy]i!T]iu]i!S]i~PC]O!j$hOx[iy[i!T[iu[i!S[i~PETO!k$iOxZiyZi!lZi!mZi!TZisZitZiuZi!SZi~O!i$gOx]Xy]X!j]X!k]X!l]X!m]X!T]Xs]Xt]Xu]X!S]X~O!j$hOx[Xy[X!k[X!l[X!m[X!T[Xs[Xt[Xu[X!S[X~O!k$iOxZXyZX!lZX!mZX!TZXsZXtZXuZX!SZX~O!l$jO!m$kOxYXyYX!TYXsYXtYXuYX!SYX~OW$lO~O{}!W!]!mjkih!ZUj~",
goto: "3l!uPPP!v!z#[PPP#h$m%]%}&x'v(w)s*z,S-Y.b/f0jPPPPPP0jPPPP0jPPP0jPPP0jP1nP0jP1q1tPPP0jP1|2UP0jP2[2_PPPPPP2bPPPPPPP2k2q2x3O3Y3`3fTjOkSiOkQqSStUuV#X!c#Z#qShOk]$tSUu!c#Z#qSiOkQnRQsTQ{VQ|WQ!s!OS#Q!^$lY#]!f#_#m#s#zQ#a!kQ#b!lQ#g!oW#i!r#w$O$RQ#u#hR#{#v!OgORTVWk!O!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$lV#P!]$b$kWfOk!]!^Y$_R!k!o#h$bs$sTVW!O!f!l!r#_#m#s#v#w#z$O$R$k$lWeOk!]!^Q#O![Q#W$XY$^R!k!o#h$bQ$o$js$rTVW!O!f!l!r#_#m#s#v#w#z$O$R$k$lYdOk![!]!^Q!}!ZQ#V$W[$]R!k!o#h$X$bQ$n$iu$qTVW!O!f!l!r#_#m#s#v#w#z$O$R$j$k$l[cOk!Z![!]!^Q!|!YQ#U$V^$eR!k!o#h$W$X$bQ$m$hw$pTVW!O!f!l!r#_#m#s#v#w#z$O$R$i$j$k$l!hbORTVWk!O!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$V$W$X$b$h$i$j$k$lV!{!X$a$g`aOk!X!Y!Z![!]!^Q!z!WQ#T$Ub$[R!k!o#h$V$W$X$a$bQ$c$f{$dTVW!O!f!l!r#_#m#s#v#w#z$O$R$g$h$i$j$k$l!``OTVWk!O!W!X!Y!Z![!]!^!f!l!r#_#m#s#v#w#z$O$R$f$g$h$i$j$k$lQ!y!UQ#S$TQ$Y$`e$ZR!k!o#h$U$V$W$X$a$b!z_ORTVWk!O!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lQ!x!TR#R$S#O^ORTVWk!O!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lQ!R]R!w!S#T[ORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$l#TZORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$l#TYORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lRvURzVQxVV#d!m#e#tQ#l!rV#|#w$O$RX#j!r#w$O$RR!P[R!u!OQ!WaQ$U$[R$f$dQkOR!`kSmPoR!bmQ!dqR#[!dQ!gsS#`!g#nR#n!sQuUR!juQ!nxR#f!nQ#x#lR$P#x",
nodeNames: "⚠ Comment Source Statement FieldDefinition FieldPath Identifier Dot Equal Expression DefaultExpression PatchExpression ComposeExpression LogicalOrExpression LogicalAndExpression ComparisonExpression ConcatExpression AdditiveExpression MultiplicativeExpression UnaryExpression PostfixExpression PrimaryExpression Literal String Integer Float True False Regex ComparisonConstraint Lt Lte Gt Gte Object LBrace Semicolon RBrace Array LBracket Comma RBracket LetExpression Let FieldDefinitionList In FunctionExpression LParen ParameterList Parameter Colon RParen Arrow MatchExpression Match MatchArm Pattern Underscore ImportExpression Import CallSuffix ArgumentList Bang Minus Star Slash Plus PlusPlus CompareOperator EqualEqual BangEqual AmpAmp PipePipe Amp SlashSlash Default",
maxTerm: 85,
skippedNodes: [0,1],
repeatNodeCount: 7,
tokenData: "=T~R!PX^$Upq$Uqr$yrs%Wst&zvw'cxy'pyz'uz{'z{|(P|}(^}!O(c!O!P(h!P!Q(m!Q![+T![!]+n!]!^+s!^!_+x!_!`,V!`!a,l!c!},y!}#O-[#P#Q-a#R#S-f#T#W,y#W#X-y#X#Y,y#Y#Z1Z#Z#],y#]#^3k#^#`,y#`#a6}#a#b8b#b#h,y#h#i:r#i#o,y#o#p<n#p#q<s#q#r=O#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~$ZY!w~X^$Upq$U#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~%OP!`~!_!`%R~%WO!h~~%ZWOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t<%lO%W~%xOg~~%{RO;'S%W;'S;=`&U;=`O%W~&XXOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t;=`<%l%W<%lO%W~&wP;=`<%l%W~'PSP~OY&zZ;'S&z;'S;=`']<%lO&z~'`P;=`<%l&z~'hP!k~vw'k~'pO!i~~'uO!P~~'zO!T~~(PO!b~~(UP!d~{|(X~(^O!e~~(cOx~~(hO!a~~(mOV~~(rW!c~OY)[Z!P)[!P!Q+O!Q#O)[#O#P)|#P;'S)[;'S;=`*x<%lO)[~)_WOY)[Z!P)[!P!Q)w!Q#O)[#O#P)|#P;'S)[;'S;=`*x<%lO)[~)|Ol~~*PRO;'S)[;'S;=`*Y;=`O)[~*]XOY)[Z!P)[!P!Q)w!Q#O)[#O#P)|#P;'S)[;'S;=`*x;=`<%l)[<%lO)[~*{P;=`<%l)[~+TO!l~~+YQh~!O!P+`!Q![+T~+cP!Q![+f~+kPi~!Q![+f~+sO!S~~+xOt~~+}Pn~!_!`,Q~,VOo~~,[QWP!_!`,b!`!a,g~,gO!g~Q,lO!UQ~,qPp~!_!`,t~,yOq~~-OSU~!Q![,y!c!},y#R#S,y#T#o,y~-aOw~~-fOy~~-mS!Z~U~!Q![,y!c!},y#R#S,y#T#o,y~.OUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y.b#Y#o,y~.gUU~!Q![,y!c!},y#R#S,y#T#Y,y#Y#Z.y#Z#o,y~/OTU~!Q![,y!c!},y#R#S,y#T#U/_#U#o,y~/dUU~!Q![,y!c!},y#R#S,y#T#i,y#i#j/v#j#o,y~/{UU~!Q![,y!c!},y#R#S,y#T#`,y#`#a0_#a#o,y~0dUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i0v#i#o,y~0}S!m~U~!Q![,y!c!},y#R#S,y#T#o,y~1`TU~!Q![,y!c!},y#R#S,y#T#U1o#U#o,y~1tUU~!Q![,y!c!},y#R#S,y#T#`,y#`#a2W#a#o,y~2]UU~!Q![,y!c!},y#R#S,y#T#g,y#g#h2o#h#o,y~2tUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y3W#Y#o,y~3_Sk~U~!Q![,y!c!},y#R#S,y#T#o,y~3pVU~!Q![,y!c!},y#R#S,y#T#a,y#a#b4V#b#c6j#c#o,y~4[UU~!Q![,y!c!},y#R#S,y#T#d,y#d#e4n#e#o,y~4sUU~!Q![,y!c!},y#R#S,y#T#c,y#c#d5V#d#o,y~5[UU~!Q![,y!c!},y#R#S,y#T#f,y#f#g5n#g#o,y~5sUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i6V#i#o,y~6^S!]~U~!Q![,y!c!},y#R#S,y#T#o,y~6qS}~U~!Q![,y!c!},y#R#S,y#T#o,y~7SUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y7f#Y#o,y~7kUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i7}#i#o,y~8US{~U~!Q![,y!c!},y#R#S,y#T#o,y~8gTU~!Q![,y!c!},y#R#S,y#T#U8v#U#o,y~8{UU~!Q![,y!c!},y#R#S,y#T#h,y#h#i9_#i#o,y~9dUU~!Q![,y!c!},y#R#S,y#T#V,y#V#W9v#W#o,y~9{UU~!Q![,y!c!},y#R#S,y#T#[,y#[#]:_#]#o,y~:fS!W~U~!Q![,y!c!},y#R#S,y#T#o,y~:wUU~!Q![,y!c!},y#R#S,y#T#f,y#f#g;Z#g#o,y~;`UU~!Q![,y!c!},y#R#S,y#T#i,y#i#j;r#j#o,y~;wUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y<Z#Y#o,y~<bSj~U~!Q![,y!c!},y#R#S,y#T#o,y~<sOs~~<vP#p#q<y~=OO!j~~=TOu~",
tokenizers: [0, 1],
topRules: {"Source":[0,2]},
tokenPrec: 2481
})
+11
View File
@@ -0,0 +1,11 @@
import { HighlightStyle } from '@codemirror/language';
import { LRLanguage, LanguageSupport } from '@codemirror/language';
export declare const decodalLanguage: LRLanguage;
export declare const decodalHighlightStyle: HighlightStyle;
export interface DecodalOptions {
highlight?: boolean;
}
export declare function decodal(options?: DecodalOptions): LanguageSupport;
@@ -64,6 +64,10 @@ export const decodalHighlightStyle = HighlightStyle.define([
{ tag: [t.brace, t.squareBracket, t.paren, t.punctuation], color: '#f9a8d4' },
]);
export function decodal() {
return new LanguageSupport(decodalLanguage, [syntaxHighlighting(decodalHighlightStyle)]);
export function decodal(options = {}) {
const { highlight = true } = options;
return new LanguageSupport(
decodalLanguage,
highlight ? [syntaxHighlighting(decodalHighlightStyle)] : [],
);
}
+10
View File
@@ -0,0 +1,10 @@
import { HighlightStyle, LRLanguage, LanguageSupport } from '@codemirror/language';
export declare const decodalLanguage: LRLanguage;
export declare const decodalHighlightStyle: HighlightStyle;
export interface DecodalOptions {
highlight?: boolean;
}
export declare function decodal(options?: DecodalOptions): LanguageSupport;
+77
View File
@@ -0,0 +1,77 @@
import { HighlightStyle, LRLanguage, LanguageSupport, foldNodeProp, indentNodeProp, syntaxHighlighting } from 'npm:@codemirror/language@^6.12.4';
import { styleTags, tags as t } from 'npm:@lezer/highlight@^1.2.3';
import { parser } from './decodal-parser-jsr.js';
const parserWithMetadata = parser.configure({
props: [
styleTags({
'Let In Match Import Default': t.keyword,
'True False': t.bool,
Identifier: t.variableName,
String: t.string,
Regex: t.regexp,
'Integer Float': t.number,
Comment: t.lineComment,
'Plus Minus Star Slash PlusPlus Equal EqualEqual Bang BangEqual Amp AmpAmp PipePipe SlashSlash Gt Gte Lt Lte Arrow': t.operator,
'LBrace RBrace': t.brace,
'LBracket RBracket': t.squareBracket,
'LParen RParen': t.paren,
'Semicolon Comma Dot Colon': t.punctuation,
}),
indentNodeProp.add({
Object: context => context.column(context.node.from) + context.unit,
Array: context => context.column(context.node.from) + context.unit,
MatchExpression: context => context.column(context.node.from) + context.unit,
LetExpression: context => context.column(context.node.from) + context.unit,
}),
foldNodeProp.add({
Object: foldDelimited('{', '}'),
Array: foldDelimited('[', ']'),
MatchExpression: foldDelimited('{', '}'),
}),
],
});
function foldDelimited(open: string, close: string) {
return (node: { from: number; to: number }, state: { doc: { sliceString(from: number, to: number): string } }) => {
const text = state.doc.sliceString(node.from, node.to);
const openIndex = text.indexOf(open);
const closeIndex = text.lastIndexOf(close);
if (openIndex < 0 || closeIndex <= openIndex) return null;
const from = node.from + openIndex + open.length;
const to = node.from + closeIndex;
return from < to ? { from, to } : null;
};
}
export const decodalLanguage: LRLanguage = LRLanguage.define({
parser: parserWithMetadata,
languageData: {
commentTokens: { line: '#' },
closeBrackets: { brackets: ['(', '[', '{', '"'] },
},
});
export const decodalHighlightStyle: HighlightStyle = HighlightStyle.define([
{ tag: t.keyword, color: '#93c5fd', fontWeight: '700' },
{ tag: t.variableName, color: 'inherit' },
{ tag: t.bool, color: '#fbbf24' },
{ tag: t.number, color: '#fbbf24' },
{ tag: t.string, color: '#86efac' },
{ tag: t.regexp, color: '#86efac' },
{ tag: t.lineComment, color: '#94a3b8', fontStyle: 'italic' },
{ tag: t.operator, color: '#f9a8d4' },
{ tag: [t.brace, t.squareBracket, t.paren, t.punctuation], color: '#f9a8d4' },
]);
export interface DecodalOptions {
highlight?: boolean;
}
export function decodal(options: DecodalOptions = {}): LanguageSupport {
const { highlight = true } = options;
return new LanguageSupport(
decodalLanguage,
highlight ? [syntaxHighlighting(decodalHighlightStyle)] : [],
);
}
+5
View File
@@ -2,4 +2,9 @@ import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'static',
vite: {
resolve: {
preserveSymlinks: true,
},
},
});
+14 -1
View File
@@ -10,12 +10,12 @@
"dependencies": {
"@astrojs/check": "^0.9.4",
"@codemirror/language": "^6.12.4",
"@codemirror/state": "^6.7.1",
"@codemirror/view": "^6.43.6",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10",
"astro": "^4.16.18",
"codemirror": "^6.0.2",
"decodal-codemirror": "file:../../packages/decodal-codemirror",
"marked": "^12.0.2"
},
"devDependencies": {
@@ -23,6 +23,15 @@
"wrangler": "^4.104.0"
}
},
"../../packages/decodal-codemirror": {
"version": "0.1.2",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@codemirror/language": "^6.12.4",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10"
}
},
"node_modules/@astrojs/check": {
"version": "0.9.9",
"resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.9.tgz",
@@ -3237,6 +3246,10 @@
}
}
},
"node_modules/decodal-codemirror": {
"resolved": "../../packages/decodal-codemirror",
"link": true
},
"node_modules/decode-named-character-reference": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
+1 -1
View File
@@ -14,12 +14,12 @@
"dependencies": {
"@astrojs/check": "^0.9.4",
"@codemirror/language": "^6.12.4",
"@codemirror/state": "^6.7.1",
"@codemirror/view": "^6.43.6",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10",
"astro": "^4.16.18",
"codemirror": "^6.0.2",
"decodal-codemirror": "file:../../packages/decodal-codemirror",
"marked": "^12.0.2"
},
"devDependencies": {
@@ -2,7 +2,7 @@
import { nav } from '../lib/docs.js';
import '../style.css';
const { title = 'Decodal', active = '', playground = false } = Astro.props;
const { title = 'Decodal', active = '', playground = false, frontpage = false } = Astro.props;
function renderNav(items, prefix = []) {
return `<ul class="nav-tree">${items
@@ -25,22 +25,27 @@ function renderNav(items, prefix = []) {
</head>
<body>
<header class="topbar">
<a class="brand" href="/docs/introduction/">Decodal</a>
<a class="brand" href="/">Decodal</a>
<nav class="topnav">
<a href="/docs/introduction/">Docs</a>
<a href="/playground/">Playground</a>
<a href="https://gitea.hareworks.net/Hare/Decodal">Source</a>
</nav>
</header>
<div class={playground ? 'layout playground-layout' : 'layout'}>
{!playground && (
<div class={playground || frontpage ? 'layout playground-layout' : 'layout'}>
{!playground && !frontpage && (
<aside class="sidebar">
<a class="sidebar-title" href="/docs/">Manual</a>
<nav set:html={renderNav(nav)} />
</aside>
)}
<main class={playground ? 'playground' : ''}>
<main class={playground ? 'playground' : frontpage ? 'frontpage' : ''}>
<slot />
</main>
</div>
<footer class="site-footer">
<span>2026 Hare</span>
<a href="https://gitea.hareworks.net/Hare/Decodal">Source</a>
</footer>
</body>
</html>
+87 -1
View File
@@ -1,3 +1,89 @@
---
return Astro.redirect('/docs/introduction/');
import ManualLayout from '../layouts/ManualLayout.astro';
const example = `Port = Int >= 1 & <= 65535 default 8080;
Server = {
host = String default "localhost";
port = Port;
};
Production = Server & {
host = "example.com";
};`;
---
<ManualLayout title="Decodal" frontpage>
<section class="hero">
<h1>Decodal keeps configuration, constraints, and defaults in one composable value.</h1>
<p class="hero-copy">
Define structured data with constraints, compose it with patches, and materialize the result from Rust,
WebAssembly, or the browser playground.
</p>
<div class="hero-actions">
<a class="button primary" href="/playground/">Try the playground</a>
<a class="button secondary" href="/docs/introduction/">Read the manual</a>
</div>
</section>
<section class="home-packages" aria-label="Official packages">
<h2>Official packages</h2>
<div class="package-links">
<a href="https://crates.io/crates/decodal">
<span>Rust crate</span>
<strong>crates.io/crates/decodal</strong>
</a>
<a href="https://www.npmjs.com/package/decodal-wasm">
<span>npm package</span>
<strong>npmjs.com/package/decodal-wasm</strong>
</a>
<a href="https://jsr.io/@hare/decodal-wasm@0.1.2">
<span>JSR package</span>
<strong>jsr.io/@hare/decodal-wasm</strong>
</a>
<a href="https://www.npmjs.com/package/decodal-codemirror">
<span>CodeMirror package</span>
<strong>npmjs.com/package/decodal-codemirror</strong>
</a>
<a href="https://jsr.io/@hare/decodal-codemirror@0.1.2">
<span>CodeMirror on JSR</span>
<strong>jsr.io/@hare/decodal-codemirror</strong>
</a>
</div>
</section>
<section class="home-grid" aria-label="Decodal overview">
<article class="home-card">
<h2>What it is</h2>
<p>
Decodal is a small data language for configuration shapes that need validation, defaults,
lazy imports, and predictable composition.
</p>
</article>
<article class="home-card">
<h2>Where it runs</h2>
<p>
Use the Rust crate for runtime embedding, the WASM package in browsers, CodeMirror/Lezer for the Web editor,
and Tree-sitter for general editor integration.
</p>
</article>
<article class="home-card">
<h2>Start here</h2>
<p>
Open the playground to run examples in your browser, or read the components page to see how the runtime and
editor pieces fit together.
</p>
<p><a href="/docs/components/">View components →</a></p>
</article>
</section>
<section class="home-example" aria-label="Decodal example">
<div>
<h2>A compact example</h2>
<p>
Constraints and defaults are values. Compose them with concrete data and materialize when the host knows what
output shape it expects.
</p>
</div>
<pre><code>{example}</code></pre>
</section>
</ManualLayout>
+1 -1
View File
@@ -1,7 +1,7 @@
import init, { evaluateProject } from '../wasm/decodal_wasm.js';
import { EditorView, basicSetup } from 'codemirror';
import { keymap } from '@codemirror/view';
import { decodal } from '../lib/codemirror/decodal.js';
import { decodal } from 'decodal-codemirror';
import { playgroundExamples } from './playground-examples.js';
const STORAGE_KEY = 'decodal-playground-project-v1';
+143 -2
View File
@@ -89,10 +89,21 @@ a:hover {
color: var(--topbar-link);
}
.site-footer {
align-items: center;
border-top: 1px solid var(--border);
color: var(--subtle);
display: flex;
font-size: 0.9rem;
gap: 14px;
justify-content: center;
padding: 15px 24px;
}
.layout {
display: grid;
grid-template-columns: 300px minmax(0, 1fr);
min-height: calc(100vh - 56px);
min-height: calc(100vh - 104px);
}
.playground-layout {
@@ -458,6 +469,130 @@ button:disabled {
white-space: nowrap;
}
.frontpage {
max-width: 1120px;
margin: 0 auto;
}
.hero {
padding: 5rem 0 4rem;
}
.hero h1 {
font-size: clamp(2.4rem, 6vw, 5rem);
line-height: 0.95;
letter-spacing: -0.06em;
margin: 0;
max-width: 950px;
}
.hero-copy {
color: var(--muted);
font-size: 1.2rem;
line-height: 1.7;
max-width: 760px;
margin: 1.5rem 0 0;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 0.9rem;
margin-top: 2rem;
}
.button {
border-radius: 999px;
font-weight: 700;
padding: 0.8rem 1.15rem;
text-decoration: none;
}
.button.primary {
background: var(--link);
color: #ffffff;
}
.button.secondary {
border: 1px solid var(--border);
color: var(--text);
}
.home-packages {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 18px;
margin-bottom: 1.5rem;
padding: 1.4rem;
}
.home-packages h2 {
margin-top: 0;
}
.package-links {
display: grid;
gap: 0.75rem;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.package-links a {
border: 1px solid var(--border);
border-radius: 14px;
display: block;
padding: 1rem;
text-decoration: none;
}
.package-links span {
color: var(--muted);
display: block;
font-size: 0.9rem;
margin-bottom: 0.3rem;
}
.package-links strong {
color: var(--text);
display: block;
font-size: 0.95rem;
overflow-wrap: anywhere;
}
.home-grid {
display: grid;
gap: 1rem;
grid-template-columns: repeat(3, minmax(0, 1fr));
margin-bottom: 1.5rem;
}
.home-card,
.home-example {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 18px;
padding: 1.4rem;
}
.home-card h2,
.home-example h2 {
margin-top: 0;
}
.home-card p:last-child,
.home-example p:last-child {
margin-bottom: 0;
}
.home-example {
display: grid;
gap: 1.5rem;
grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
}
.home-example pre {
margin: 0;
}
@media (max-width: 900px) {
.layout {
grid-template-columns: 1fr;
@@ -467,7 +602,13 @@ button:disabled {
border-right: 0;
max-height: 260px;
}
.playground-shell {
.playground-shell,
.home-grid,
.home-example,
.package-links {
grid-template-columns: 1fr;
}
.hero {
padding-top: 3rem;
}
}
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
{
"name": "@hare/decodal-wasm",
"version": "0.1.2",
"license": "MIT",
"exports": "./decodal_wasm.js",
"publish": {
"include": [
"README.md",
"decodal_wasm.js",
"decodal_wasm.d.ts",
"decodal_wasm_bg.wasm",
"package.json"
]
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "decodal-wasm",
"type": "module",
"description": "WebAssembly wrapper for evaluating Decodal in browser playgrounds.",
"version": "0.1.1",
"version": "0.1.2",
"license": "MIT OR Apache-2.0",
"repository": {
"type": "git",