Bahasa DSL

DSL nuforge adalah bahasa deklaratif kecil untuk mendeskripsikan halaman. Sebuah program adalah daftar global dan komponen; nuforge mem-parsing-nya menjadi AST reaktif. Halaman ini menelusuri seluruh sintaksnya.

Global

Gunakan val di tingkat teratas untuk mendeklarasikan nilai bersama. Nilai tersebut dapat menampung ekspresi apa pun yang diizinkan, termasuk objek:

val brand = "nuforge";
val theme = { primary: "#0066DE" };

Komponen

Sebuah komponen memiliki props dengan nilai default di dalam tanda kurung, state lokal yang dideklarasikan dengan val di dalam kurung kurawal, dan template setelah =>:

component App(title = "Untitled") {
  val count = 0;
  val items = ["a", "b"];
} => (
  <div>
    <h1>{title}</h1>
  </div>
)

Blok props, blok state, dan template masing-masing bersifat opsional, tetapi sebuah komponen selalu mendeklarasikan template-nya setelah panah =>.

Teks dan ekspresi

Di dalam template, kurung kurawal menampung ekspresi. Sebuah literal string seperti {"a static string"} me-render teks statis, sedangkan {expr} mengevaluasi ekspresi dinamis seperti {count}. Template literal didukung — tulis di dalam backtick di dalam sebuah ekspresi:

<p>{`Hello, ${title}`}</p>

Atribut

Atribut menerima ekspresi di dalam kurung kurawal. Gunakan literal string untuk nilai konstan, atau ekspresi apa pun untuk nilai dinamis:

<div class={"page"} id={someId} data-count={count} />

Anda menulis nama atribut HTMLclass dan for, bukan className / htmlFor. DSL mendeskripsikan markup, jadi ia tetap netral terhadap framework (HTML dan Vue juga memakai class). Adapter React memetakan classclassName dan forhtmlFor saat render, dan ekspor kode melakukan hal yang sama — jadi class={"page"} menjadi className="page" pada React yang dihasilkan.

Inline styles

Tag <style> (atau <script>) mempertahankan isinya sebagai teks mentah, jadi Anda bisa menulis CSS asli — pakai string backtick untuk aturan multi-baris dan combinator:

<style>{`
  .card { padding: 1rem; border-radius: 8px; }
  .card > .title { font-weight: 700; }
`}</style>

Untuk sebagian besar styling, utamakan utility class (class={"..."}); pakai <style> saat butuh aturan CSS sungguhan. Untuk membatasi style hanya ke kanvas editor, gunakan prop srcDoc / baseCss pada IframeCanvas (lihat SDK Editor).

Direktif

Direktif adalah atribut khusus yang mengontrol rendering:

  • @if={cond} me-render elemen secara kondisional.
  • @each={item in list} atau @each={(item, index) in list} mengulang elemen untuk setiap entri.
  • @classList={{ active: count > 0 }} mengalihkan kelas berdasarkan kondisi.
<li @each={(item, index) in items} @classList={{ first: index == 0 }}>{item}</li>

Two-way binding

Binding value:={...} menjaga input tetap terkontrol dan menulis suntingan pengguna kembali ke state:

<input value:={name} />

Event

Penangan event adalah arrow function. Mereka dapat menulis ke state secara langsung:

<button onClick={() => count = count + 1}>{count}</button>

Komposisi

Sebuah tag yang namanya diawali huruf kapital adalah instance komponen. Berikan props sebagai atribut:

<Card title={"Hi"} />

Externals

Identifier yang diawali $ merujuk ke nilai yang disediakan host. Gunakan $state untuk state eksternal, $func(...) untuk memanggil fungsi host, dan <$Component/> untuk me-render komponen eksternal:

<$Component label={$state} onPick={() => $func("pick")} />

Lihat halaman externals untuk cara mendaftarkan ini dari host.

Apa yang diizinkan

Demi keamanan, parser hanya menerima sekumpulan node ekspresi yang dikenal: literal, identifier, akses member, array, objek, operator binary / logical / unary, ekspresi kondisional (ternary), pemanggilan fungsi, arrow function (untuk event), dan template literal.

Parser MENOLAK apa pun di luar allow-list tersebut, termasuk:

  • new, function, this, typeof, dan delete
  • operator strict-equality — tulis == / !=, yang saat diekspor dikompilasi menjadi === / !==
  • increment dan decrement ++ / --
  • comma sequence dan tagged template
  • akses ke constructor, __proto__, atau prototype

Lihat halaman security untuk jaminan lengkap di balik aturan-aturan ini.

Parser.diagnose(source) memvalidasi DSL tanpa melempar error — ia mengembalikan daftar diagnostik terstruktur (kosong jika valid), tiap item berisi pesan, sebuah code, dan rentang offset sumber plus baris/kolom:

import { Parser } from '@nuforge/parser';

Parser.diagnose(`component App() {} => (<div>{new Date()}</div>)`);
// [{ severity: 'error', code: 'forbidden-syntax',
//    message: 'Syntax "NewExpression" is not allowed',
//    from, to, start: { line, column }, end }]

Komponen @nuforge/react-code-editor (CodeEditor) dibangun di atas ini: ia menyediakan autocomplete DSL nuforge (keyword, directive, tag HTML, serta nama component/state/prop/global dan $external dari program Anda) dan squiggle error langsung yang ditenagai diagnose.

Langkah berikutnya

  • Runtime — evaluasi AST menjadi pohon View dengan sebuah Frame.
  • Externals — daftarkan state, fungsi, dan komponen host.