コード編集

このプラグインは、ReScript コードの記述をより生産的にする豊富な編集機能を提供します。

コード折りたたみ

Native

ブロックを折りたたんだり展開したりして、重要なコードに集中できます。

折りたたみ可能な要素

  • モジュール宣言 — module Name = { ... }

  • Let バインディング — { ... } を含む複数行の let

  • 型定義 — 複数行の type 宣言

  • ブロックコメント — /* ... */

  • カスタムリージョン — //#region ... //#endregion

カスタムリージョン

//#region と //#endregion マーカーを使用してカスタムの折りたたみ可能なセクションを作成できます:

//#region Helper functions
let add = (a, b) => a + b
let multiply = (a, b) => a * b
//#endregion

コード折りたたみにより実装の詳細を隠して重要な宣言に集中でき、大きなファイルを分割せずにナビゲーション可能にします。

コードフォーマット

フォーマットとフォーマットチェックは入出力を並行処理し、コマンド全体に10秒のタイムアウトと出力ストリームごとに4 MiBの上限を適用します。取消時には所有プロセスと観測済みの子プロセスを停止します。タイムアウトや出力上限超過時にはドキュメントを変更せず、失敗理由を通知します。

LSP Required

Ctrl+Alt+L(macOS では Cmd+Option+L)を押して、rescript format CLI を使用して現在のファイルをフォーマットします。

仕組み

プラグインは現在のドキュメント内容を rescript format --stdin .<ext> に stdin 経由でパイプし、フォーマットされた出力でドキュメントテキストを置き換えます。.res と .resi の両方のファイルに対応しています。フォーマットは IntelliJ の AsyncDocumentFormattingService を通じて非同期で実行されるため、操作中もエディターの応答性が維持されます。

要件

ReScript コンパイラ(rescript)がプロジェクトの node_modules にインストールされている必要があります。プラグインはファイルのディレクトリからプロジェクトルートまで CLI を検索します。CLI が見つからない場合は、通知が表示されます。

エラーハンドリング

  • CLI が見つからない --- rescript が node_modules に見つからなかったことを示す通知が表示されます

  • タイムアウト --- フォーマットに 10 秒以上かかった場合、プロセスが終了しエラー通知が表示されます

  • フォーマッターエラー --- フォーマッターがゼロ以外のコードで終了した場合(例: ファイル内の構文エラー)、stderr 出力が通知として表示されます

保存時フォーマット

保存時に ReScript ファイルを自動フォーマットするには、Settings > Tools > Actions on Save で Reformat code を有効にします。

参考

コード分析 --- Format Check はフォーマットされていないファイルをハイライトし、フォーマットのクイックフィックスを提供できます。

ショートカット一つでファイル全体を公式 ReScript スタイルにフォーマットでき、手動のスペース調整を排除してチーム全体で一貫したコードスタイルを確保します。

括弧のマッチング

Native

エディターは対応する括弧のペアをハイライトします:

  • { と }

  • [ と ]

  • ( と )

ブレースマッチングによりブロックの開始と終了を即座に確認でき、深くネストされたコードでのデリミタの不一致を防ぎます。

スマート引用符

Native

", ', または ` を入力すると、閉じ引用符が自動的に挿入されます。

自動ペアリング引用符によりキーストロークを節約し、文字列デリミタの不一致による一般的な構文エラーを防ぎます。

Smart Enter

Native

Shift+Enter を押すと、現在の文をインテリジェントに補完し、新しい行を開始します:

  • 閉じられていない括弧やブレースを閉じます

  • 不足している switch の本体ブレースを追加します

  • カーソルを適切な位置に移動します

Smart Enter は開いた構文をインテリジェントに閉じてカーソルを配置するため、デリミタを手動でバランスさせることなく次の文を入力し続けられます。

コメントの切り替え

Native

  • Ctrl+/ — 行コメントの切り替え(//)

  • Ctrl+Shift+/ — ブロックコメントの切り替え(/* */)

コメントデリミタを手動で入力・削除することなく、デバッグやコードの一時的な無効化のためにコメントを素早くオン・オフ切り替えできます。

ステートメントの移動

Native

トップレベル宣言を上下に移動します:

  • Alt+Shift+Up — 宣言を上に移動

  • Alt+Shift+Down — 宣言を下に移動

これにより、宣言全体(デコレーターを含む)がひとつの単位として移動されます。

カット&ペーストなしで宣言を並べ替えられます — ムーバーはデコレータを含む宣言ブロック全体を処理するため、アノテーションを置き忘れたり複数行の定義を壊すことがありません。

インテンションアクション

Native

式の上で Alt+Enter を押すと、利用可能なインテンションが表示されます:

インテンション

説明

Some(...) でラップ

式を Some() でラップ

Ok(...) でラップ

式を Ok() でラップ

Error(...) でラップ

式を Error() でラップ

@genType を追加

宣言に @genType アノテーションを追加

ドキュメントコメントの生成

宣言の上に /** */ ドキュメントコメントのスタブを挿入

パイプを関数呼び出しに変換

arr->Array.map(f) を Array.map(arr, f) に変換

関数呼び出しをパイプに変換

Array.map(arr, f) を arr->Array.map(f) に変換

インターフェースに公開

.res の宣言を対応する .resi インターフェースファイルに追加

インターフェースから非公開

.resi インターフェースファイルから宣言を削除

ラベル付き引数を挿入

関数呼び出しのすべてのラベル付き引数を挿入

Switch ケースの統合

同じボディを持つ switch ケースを | A | B => body に統合

ネスト switch の平坦化

本体がアーム束縛に対するネスト switch だけで構成されたアームを 1 階層に統合する

ケースの分割

パターン変数をすべてのコンストラクターケースに展開

ラベル付き引数に変換

位置引数をラベル付き引数に変換

不要な括弧を削除

証明できるスカラー初期値の括弧を除去する

冗長な修飾子を削除

不要なモジュールパスの修飾子を削除

open を修飾参照に展開

プロジェクト内の open M が導入したメンバ参照を明示的な M.name 形に書き戻し、open 文を削除する

filter+map を filterMap に変換

->Array.filter(f)->Array.map(g) を ->Array.filterMap(...) に変換

型注釈を追加

LSP hover の情報を使用して let バインディングに明示的な型注釈を追加

推論された型注釈の一括挿入

LSP hover の情報を使用して、ファイル内の注釈なしトップレベル let すべてに推論された型注釈を一括挿入する

->ignore を追加

式の戻り値を破棄するために ->ignore を末尾に追加

_ プレフィックスを追加

未使用変数の警告を抑制するためにアンダースコアプレフィックスを追加

冗長なブレースを削除

単一式を囲む不要な { } を削除

識別子のケースを修正

識別子のケースを修正(例: 値は小文字開始、モジュールは大文字開始)

分割代入の展開

let {a, b} = x を個別の let バインディングに展開

呼び出しを uncurried 形式に変換

f が uncurried 構文 let f = (. x) => ... で定義されている場合、f(x) を f(. x) に書き換えます

モジュールをファイルに抽出

トップレベルの module M = {{ ... }} 宣言を、隣接する M.res ファイルに移動します

variant constructor のリネーム(プロジェクト全体、LSP 不要)

トークン形状分類器を使ってプロジェクト内のすべての .res / .resi ファイルにまたがって variant constructor をリネームします。language server なしでも動作します

Intention アクションは一般的なコード変換をワンクリック操作に変えます — 手動でコードを再構成する代わりに、Alt+Enter を押して IDE に機械的な変更を任せ、ロジックに集中できます。

参考

Code Analysis では、問題を自動的に検出するインスペクションと、ワンクリックで解決できるクイックフィックスを提供しています。

Some(...) でラップ

選択した式を Some() でラップします。プレーンな値を option 型に変換する必要がある場合に便利です。

式を選択し、Alt+Enter を押して、Wrap with Some(...) を選択します。

name を選択してから:

let name = "Alice"
let greeting = getGreeting(name)
let name = "Alice"
let greeting = getGreeting(Some(name))

Ok(...) でラップ

選択した式を Ok() でラップします。result 型を使用する関数から成功値を返す場合に便利です。

value を選択してから:

let value = computeResult()
let response = processResponse(value)
let value = computeResult()
let response = processResponse(Ok(value))

Error(...) でラップ

選択した式を Error() でラップします。result 型を使用する関数からエラー値を返す場合に便利です。

2行目の message を選択してから:

let message = "Something went wrong"
let result = message
let message = "Something went wrong"
let result = Error(message)

@genType を追加

let, type, または module 宣言の上に @genType アノテーションを追加します。このアノテーションは ReScript コンパイラに宣言の TypeScript 型定義を生成するよう指示し、TypeScript コードとのシームレスな相互運用を可能にします。

このインテンションは、まだ @genType アノテーションが付与されていない宣言でのみ利用可能です。

let greet = (name: string) => `Hello, ${name}!`
@genType
let greet = (name: string) => `Hello, ${name}!`

これは型宣言やモジュール宣言にも使用できます:

type user = {
  name: string,
  age: int,
}
@genType
type user = {
  name: string,
  age: int,
}

ドキュメントコメントの生成

現在の宣言の上に /** ... */ ドキュメントコメントのスタブを挿入します。関数宣言の場合、各パラメーターに対して @param タグが自動的に生成されます。

このインテンションは、まだドキュメントコメントが付与されていない let、type、module、external、exception 宣言で利用可能です。

let add = (~a: int, ~b: int) => a + b
/**
 *
 * @param a
 * @param b
 */
let add = (~a: int, ~b: int) => a + b

パイプ ⇔ 関数呼び出しの変換

パイプファースト構文と通常の関数呼び出し構文を相互変換します。パイプ式または関数呼び出しにキャレットを置いて Alt+Enter を押します。

パイプから関数呼び出しへ:

// Before
arr->Array.map(x => x + 1)

// After
Array.map(arr, x => x + 1)

関数呼び出しからパイプへ:

// Before
Array.map(arr, x => x + 1)

// After
arr->Array.map(x => x + 1)

unit 呼出しは保持されます。getItems()->Array.length は Array.length(getItems()) に変換され、逆変換すると getItems()->Array.length に戻ります。ネストした引数、文字列、コメント、配列/レコード、複数行の式のソーステキストを保持します。1 回の undo で元の式に戻ります。

この Intention は -> と位置引数を持つ修飾された関数呼出しを扱います。文字列/コメント内、|>、ラベル付き/省略可能な引数、プレースホルダー、JSX/テンプレート、不完全な区切り、曖昧な演算子境界では提供されません。複雑な式は変換前に括弧で囲んでください。未対応の入力は変更しません。

items => items->Array.length のような通常の位置パラメーターを持つ lambda 本体内でも変換できます。型付き/分割代入の lambda パラメーターと文を含むブロックには現在対応していません。引数の形状を再帰的に確認し、Array.map(arr, a b) のように括弧が釣り合っていても解釈できない入力は変換しません。

インターフェースの公開/非公開

.res 実装から直接、.resi インターフェースファイルで公開する宣言を制御します。

Publish to interface: .res ファイルの let、type、module、または external 宣言にキャレットを置いて Alt+Enter を押し、Publish to interface を選択します。宣言のシグネチャが対応する .resi ファイルに追加されます。

Unpublish from interface: .resi ファイルに存在する宣言にキャレットを置いて Alt+Enter を押し、Unpublish from interface を選択します。対応する宣言が .resi ファイルから削除されます。

注釈

これらのインテンションには対応する .resi ファイルが必要です。必要に応じて、先に Create Interface File で生成してください。

ラベル付き引数の挿入

ラベル付き引数を持つ関数を呼び出す際、関数呼び出しの括弧内にキャレットを置いて Alt+Enter を押し、Insert labeled arguments を選択します。すべてのラベル付き引数が名前付きパラメーターとして挿入されます。

makeUser()
makeUser(~name, ~age, ~role)

Switch ケースの統合

複数の switch ケースが同じボディを持つ場合、いずれかにキャレットを置いて Alt+Enter を押し、Merge switch cases を選択します。ケースが複数のパターンを持つ単一のアームに統合されます。

switch status {
| Active => "valid"
| Pending => "valid"
| Inactive => "invalid"
}
switch status {
| Active | Pending => "valid"
| Inactive => "invalid"
}

ネスト switch の平坦化

switch アームが値を束縛し、その本体が同じ束縛に対する別の switch だけで構成されている場合、2 つの階層を 1 つに統合できる。外側アームにキャレットを置いて Alt+Enter を押し、Flatten nested switch を選択する。内側の各パターンが外側パターンの束縛位置に折り込まれるため、| Some(y) => switch y { ... } は内側のケースごとに 1 つの平坦化されたアームを生成する。

switch outer {
| Some(y) =>
  switch y {
  | Some(z) => use(z)
  | None => fallback
  }
| None => empty
}
switch outer {
| Some(Some(z)) => use(z)
| Some(None) => fallback
| None => empty
}

この intention は純粋に構文ベースで、言語サーバーなしで動作する。外側アームの束縛がちょうど 1 つで、本体がその束縛に対する内側 switch のみであり、いずれの switch も when ガードや内側の or-pattern を使っていない場合にのみ提示される。

ケースの分割

パターンマッチの変数をすべてのコンストラクターケースに展開します。switch アームの変数パターンにキャレットを置いて Alt+Enter を押し、Case split を選択します。

switch option {
| x => handle(x)
}
switch option {
| Some(value) => handle(Some(value))
| None => handle(None)
}

不足している switch アームの追加

既存の switch でまだカバーされていない variant コンストラクターを補完します。書きかけの switch の switch キーワード上(またはスクラティニー式のどこか)にキャレットを置いて Alt+Enter を押し、Add missing switch arms を選択します。Intention は LSP hover でスクラティニーの型を取得し、variant のコンストラクター集合と 既存アームの差集合を計算して、不足している各コンストラクターのスケルトンアームを閉じ } の直前に挿入します。switch がワイルドカード _ のアーム、または素の小文字バインディングパターンをすでに含む場合、それらは switch を網羅的にするため Intention は表示されません。or-pattern (| Foo | Bar => ...) は両方のコンスト ラクターをカバー済みとして扱います。ネストした switch では、キャレットを含む最も内側の switch のみが対象になります。

LSP の hover が | Red | Blue のようなインライン variant 本体ではなくcolor や status のような単なる型名のみを返した場合 (ユーザー定義 variant に対して ReScript LSP が通常返す形式)、Intention はプロジェクト全体の stub index 検索にフォールバックします。RescriptNameIndex から hover された識別子に一致する type <name> = ... 宣言を引き、右辺を標準の type 宣言パーサーで再パースし、得られたコンストラクター集合を不足 arm 計算の差集合に流し込みます。このフォールバックは静かに動作し、必要なときだけ走るので、「variant がプロジェクト内の別ファイルで定義されている」という典型ケースでIntention が成功するようになりました。

let describe = (x: option<int>) =>
  switch x {
  | Some(v) => Belt.Int.toString(v)
  }
let describe = (x: option<int>) =>
  switch x {
  | Some(v) => Belt.Int.toString(v)
  | None => todo
  }

ラベル付き引数への変換

位置引数をラベル付き引数に変換します。関数呼び出しにキャレットを置いて Alt+Enter を押します。

makeUser("Alice", 30, "admin")
makeUser(~name="Alice", ~age=30, ~role="admin")

不要な括弧の削除

単純な let 束縛の初期値全体を構成するスカラーリテラルまたは単独の識別子の括弧を除去します。外側の括弧にカーソルを置き、Alt+Enter を押してください。文字列とコメントを保持し、1回の undo で元に戻せます。

let x = (42)
let x = 42

呼出し・タプル・unit 値・lambda 引数・パターン・型注釈・入れ子の括弧・演算式(比較と pipe を含む)は拒否します。type・module・external 宣言、注釈、テンプレート、JSX を含むファイルは対応範囲外です。括弧が冗長であることを確認できない場合はコードを変更しません。

冗長な修飾子の削除

先行する open と同じファイル内の直接宣言された module により、修飾を外した値が同一 binding を指すと証明できる場合にのみ qualifier を除去します。module 識別子にキャレットを置き、Alt+Enter を押してください。module の export は名前が一意なスカラーリテラルに限定され、ファイルも対応するトップレベル宣言/値構文を使う必要があります。

module A = { let value = 1 }
open A
let result = A.value
module A = { let value = 1 }
open A
let result = value

外部 module、alias/re-export、後方または競合する open、include、同名 binding による shadowing、入れ子 scope、型注釈、未対応構文では拒否します。文字列とコメントを open や参照として扱いません。間にあるコメントは保持し、1 回の undo でソースを戻せます。availability の確認後に文書が変更された場合、準備済みの変更は適用されません。

open を修飾参照に展開

Remove Redundant Qualifier の逆方向の操作。open M が導入したメンバ参照を明示的な M.name 形に書き戻し、不要になった open 文を削除する。open M の行にキャレットを置いて Alt+Enter を押す。

この機能は純粋に構文ベースで動作し、language server を必要としない。M がプロジェクト内のソースファイル (M.res / M.resi) として解決できる場合のみ利用でき、修飾するメンバはそのファイルのトップレベル宣言から取得する。Belt のような (node_modules から解決される) ライブラリモジュールは対象外で、その場合 intention は表示されない。既に修飾済みの参照や、後続のローカル束縛でシャドウされたメンバはそのまま残す。

open M

let x = foo(bar)
let x = M.foo(M.bar)

filter+map を filterMap に変換

->Array.filter(f)->Array.map(g) チェーンを単一の ->Array.filterMap(...) 呼び出しに変換します。filter または map の呼び出しにキャレットを置いて Alt+Enter を押します。

items
->Array.filter(x => x > 0)
->Array.map(x => x * 2)
items->Array.filterMap(x => {
  if x > 0 {
    Some(x * 2)
  } else {
    None
  }
})

型注釈の追加

LSP hover の型情報を使用して let バインディングに明示的な型注釈を追加します。let バインディングにキャレットを置いて Alt+Enter を押します。

let name = "Alice"
let name: string = "Alice"

推論された型注釈の一括挿入

Add type annotation をバインディングごとに呼び出すのではなく、現在のファイル内の注釈なしトップレベル let すべてを 1 回でまとめて注釈します。ファイル内の任意の位置にキャレットを置いて Alt+Enter を押し、Insert inferred type annotations を選択します。IDE は各推論型を LSP hover から解決し、すべての挿入を 1 回の取り消し可能な操作として適用します。

同じアクションは Type Coverage Heat Map ツールウィンドウからも利用できます。テーブルでカバレッジの低いファイルを選択し、Insert Inferred Types ツールバーボタンをクリックすると、ファイルを開かずに注釈を付けられます。

let greeting = "hello"
let count = 42
let double = x => x * 2
let greeting: string = "hello"
let count: int = 42
let double: int => int = x => x * 2

すでに注釈を持つバインディングはそのまま残されます。言語サーバーが安定した注釈として表現できない型 — '_a のような弱い型変数や、Markdown の残りを含む hover テキスト — はスキップされ、結果バルーンが注釈を付けたバインディング数とスキップした数を報告します。このアクションには稼働中の言語サーバーが必要です。

->ignore を追加

戻り値が使用されていない式に ->ignore を追加し、破棄された値に関するコンパイラ警告を抑制します。式にキャレットを置いて Alt+Enter を押します。

Js.log("debug message")
Array.push(items, newItem)
Js.log("debug message")->ignore
Array.push(items, newItem)->ignore

_ プレフィックスを追加

変数名にアンダースコアプレフィックスを追加して、意図的に未使用であることを示します。これによりコンパイラの未使用変数警告が抑制されます。未使用の変数にキャレットを置いて Alt+Enter を押します。

let result = someComputation()
let _result = someComputation()

冗長なブレースの削除

単一の式を囲む不要な { } を削除します。ブレースにキャレットを置いて Alt+Enter を押します。

let greet = (name) => {
  "Hello, " ++ name
}
let greet = (name) => "Hello, " ++ name

識別子ケースの修正

ReScript の規約に従って識別子のケースを修正します: 値と関数は小文字で始まり、モジュールとバリアントコンストラクターは大文字で始まる必要があります。命名が不適切な識別子にキャレットを置いて Alt+Enter を押します。

let MyValue = 42
let myValue = 42

分割代入の展開

分割代入された let バインディングを各フィールドごとの個別の let バインディングに展開します。分割代入パターンにキャレットを置いて Alt+Enter を押します。

let {name, age, email} = user
let name = user.name
let age = user.age
let email = user.email

呼び出しを uncurried 形式に変換

対象関数が旧来の uncurried 構文 let f = (. x) => ... で定義されている場合に、curried な呼び出し箇所を uncurried 形式 f(. x) に書き換えます。ReScript v10 / v11 コードベースでの LSP applyUncurried quick fix のネイティブフォールバックとして提供されます。

呼び出し箇所の識別子にキャレットを置いて Alt+Enter を押し、Convert call to uncurried form を選択します。

let add = (. x, y) => x + y
let result = add(1, 2)
let add = (. x, y) => x + y
let result = add(. 1, 2)

Intention はスタブインデックスで最初にマッチした定義のみを参照します。引数なし形式 f() は f(.) に書き換えられます。

モジュールをファイルに抽出

トップレベルの module M = {{ ... }} 宣言を現在のファイルから取り出し、隣接する M.res ファイルに移動します。Language Server の WorkspaceEdit.CreateFile 操作が IDE 側で完全に処理されない場合に、LSP extractLocalModuleToFile code action のネイティブフォールバックとして提供されます。

モジュール宣言の名前部分にキャレットを置いて Alt+Enter を押し、Extract module to file を選択します。

module Inner = {
  let value = 42
  let double = x => x * 2
}

let total = Inner.double(Inner.value)

Foo.res:

let total = Inner.double(Inner.value)

Inner.res(新規作成):

let value = 42
let double = x => x * 2

Intention は抽出したモジュールへの参照を元ファイル内で書き換えません。そのような参照が検出された場合は警告バルーンが表示され、呼び出し箇所を手動で調整(例: open Inner の追加や修飾パスの更新)できます。隣接する Inner.res ファイルが既に存在する場合は Intention は表示されません。

Surround With(囲む)

Native

コードを選択して Ctrl+Alt+T を押すと、以下で囲むことができます:

  • if 式

  • switch 式

  • try / catch ブロック

  • ブロックスコープ { ... }

  • JSX 要素 <div>...</div>

  • JSX フラグメント <>...</>

if 式

選択したコードを if ブロック内にラップします。カーソルは condition プレースホルダーに配置されるため、すぐに条件を入力できます。

Js.log("hello") を選択してから:

Js.log("hello")
if (condition) {
  Js.log("hello")
}

switch 式

選択したコードをデフォルトの _ アームを持つ switch 式内にラップします。カーソルは expr プレースホルダーに配置されるため、マッチする式をすぐに入力できます。

defaultHandler() を選択してから:

defaultHandler()
switch expr {
| _ => defaultHandler()
}

try / catch ブロック

選択したコードを try / catch ブロックでラップします。カーソルは catch アームの () プレースホルダーに配置されるため、エラー処理ロジックをすぐに定義できます。

parseJson(input) を選択してから:

parseJson(input)
try {
  parseJson(input)
} catch {
| exn => ()
}

ブロックスコープ { ... }

選択したコードをブロックスコープでラップします。変数のスコープを制限したり、式をグループ化する場合に便利です。

2行を選択してから:

let temp = calculate()
process(temp)
{
  let temp = calculate()
  process(temp)
}

JSX 要素
...

選択したマークアップを <div> 要素でラップします。カーソルは開きタグ名 div を選択するため、目的の要素名にすぐにリネームできます。

<Greeting name /> を選択してから:

<Greeting name />
<div>
  <Greeting name />
</div>

JSX フラグメント <>...</>

選択したマークアップを JSX フラグメント <>...</> でラップします。余分な DOM ノードを追加せずに兄弟要素をグループ化できます。

2行を選択してから:

<Header />
<Body />
<>
  <Header />
<Body />
</>

Surround With はショートカット一つで選択コードを制御構造で囲み、囲む構文を手動で入力したり囲まれたコードを再インデントする手間を省きます。

参考

Code Completion では、同様のコード生成パターンのための Postfix テンプレート(.switch、.pipe)と Live Template を提供しています。

インポートの最適化

Native

Ctrl+Alt+O を押すと、現在のファイルのインポートを最適化します。

仕組み

Import Optimization は、同じスコープ内で参照先が確認できるローカルモジュールを隣接して繰り返し open した場合だけ、後方の open を削除します。現在はリテラルの let 束縛だけを含み、モジュールを export しないモジュールに対応します。open の間にあるコメントや空白は許容します。

別の open や宣言の後で再びモジュールを open すると参照先が変わり得るため、その open は保持します。未知の参照先・エイリアス・入れ子のモジュールを export する場合も保持します。インスペクションと Quick Fix は同じ確認処理を使い、Quick Fix は編集前に現在のソースを再確認します。

設定

unused-open 警告だけに基づく自動削除は、警告が古いソースのものかもしれないため停止しています。保存した Remove unused opens の設定は保持し、操作欄は無効にします。現在の意味に基づく確認がない限り削除しません。確認できない場合はソースを変更しません。

例

module A = {let value = 1}
open A
open A
Console.log(value)
module A = {let value = 1}
open A
Console.log(value)

リネーム

LSP Required

Shift+F6 を押すと、プロジェクト全体でシンボルをリネームします。Language Server がすべての参照を検索して更新します。

リネームリファクタリングはプロジェクト全体のすべての参照を一括更新し、手動の検索と置換で残る見落としや不整合なリネームのリスクを排除します。

変数の抽出

Native

Ctrl+Alt+V(macOS では Cmd+Alt+V)を押して、選択した式を let バインディングに抽出します。

ハンドラーは let 宣言本体内の選択された式を検出し、現在のステートメントの上に新しい let バインディングを作成し、元の式を新しい変数への参照に置き換えます。

a + b を選択してから:

let calculate = (a, b) => {
  let result = a + b * 2
  result
}
let calculate = (a, b) => {
  let sum = a + b
  let result = sum * 2
  result
}

Extract Variable により中間式に名前を付けて明確にでき、周囲のコードを手動で再構成することなく複雑な式を自己文書化できます。

関数の抽出

Native

Ctrl+Alt+M(macOS では Cmd+Alt+M)を押して、選択したコードを新しい関数に抽出します。

ハンドラーは対応する字句束縛への参照を解決し、選択した式または文を同じブロック内の選択した文の直前に置く新しい let 関数へ抽出します。選択範囲外で宣言された束縛だけを引数化します。文字列・コメント・修飾されたメンバー・レコードのラベルは引数にしません。宣言と呼出しを単一の取り消し可能なコマンドで編集し、生成名は既存の識別子との衝突を避けます。トップレベルの補助関数は private とし、export する宣言全体の選択は拒否します。

a + b を選択してから:

let calculate = (a, b) => {
  let result = a + b
  result * 2
}
let calculate = (a, b) => {
  let extractedFunction = (a, b) => {
    a + b
  }

  let result = extractedFunction(a, b)
  result * 2
}

単純な let 束縛とブロック本体を持つ lambda の引数に対応します。選択内の局所束縛は抽出した関数内に残し、選択外で使われる場合は抽出を拒否します。再束縛・分解束縛・選択内の lambda 値・型を確認できない field 値・単独の module member・constructor・部分適用・open・module・テンプレート・生の JavaScript・省略ラベル・汎用化されている可能性のある束縛(関数呼び出しの結果を含む)・未解決名は安全のため拒否します。必要な型や挿入位置の文脈を確認できないため、レコードリテラル・配列と添字式・プレースホルダー・戻り値の型注釈・文の継続部分にまたがる選択も拒否します。プロジェクト全体の完全な意味に基づく解決にはまだ対応していません。field の読取と更新は確認できた ref initializer の .contents に限定します。呼出しと ref 更新は抽出した本体に残り、元の呼出し位置で1回実行します。

定数のインライン化

Native

単一行の let 宣言上で Ctrl+Alt+N(macOS では Cmd+Alt+N)を押すと、リテラルだけからなる定数式をインライン化します。

ハンドラーは字句スコープを検証し、識別子の参照だけを置換して、文字列・コメント・修飾されたフィールドを保持します。式の優先順位を保つため、置換する式には必ず括弧を付けます。ローカル宣言は同じ取り消し可能なコマンドで削除し、トップレベル宣言は他のモジュールから利用できるよう保持します。

呼び出し・変数に依存する式・除算・複数行の宣言・宣言上のコメント・型注釈には対応しません。再束縛・未解決のパターン・テンプレート・生の JavaScript・eval・注釈・open・module を含むファイルは、意味に基づく参照解決がサポートされるまで安全のため利用できません。選択した名前を隠す引数・レコードの省略記法・ラベル付き引数は、役割を確認できない場合は拒否します。

let result = {
  let sum = 1 + 2
  sum * 3
}
let result = {
  (1 + 2) * 3
}

結果は 9 のままで、1 回の取り消しで宣言と編集したすべての参照を復元します。

定数の導入

Native

リテラル値をモジュールレベルの定数に抽出します。文字列、数値、その他のリテラルを選択して Refactor > Introduce Constant を使用します。

ハンドラーは選択したリテラルをファイルの先頭(open 文の後)に新しい let バインディングとして抽出し、元のリテラルを新しい定数への参照に置き換えます。

"Hello, World!" の定数導入:

let greeting = "Hello, World!"
let farewell = "Goodbye, World!"
let helloWorld = "Hello, World!"
let greeting = helloWorld
let farewell = "Goodbye, World!"

Introduce Constant はマジック値をモジュールレベルの名前付きバインディングに抽出し、意図を明示的にしてファイル全体での再利用を可能にします。

シグネチャの変更

Native

Ctrl+F6 を押して関数のパラメーターを変更(並べ替え、リネーム、追加、削除)し、ファイル内の呼び出し箇所を更新します。

ハンドラーはキャレット位置の関数宣言を解析し、ラベル付き(~name: type)と位置パラメーターの両方をサポートし、宣言とすべての対応する呼び出し箇所に変更を適用します。

パラメーターの並べ替え:

let make = (~name: string, ~age: int) => { name, age }

let user = make(~name="Alice", ~age=30)
let make = (~age: int, ~name: string) => { name, age }

let user = make(~age=30, ~name="Alice")

Change Signature は関数のパラメータリストを再構成し、すべての呼び出し箇所を自動更新するため、API の進化がエラーの起きやすい手動編集ではなく安全で機械的になります。

React コンポーネントの抽出

Native

選択した JSX を新しい React コンポーネントに抽出します。JSX 式を選択し、Refactor > Extract React Component を使用します。

ハンドラーは選択した JSX を本体とする新しい @react.component モジュールを作成します。選択範囲内で使用されている props が検出され、新しいコンポーネントの make 関数にラベル付きパラメーターとして追加されます。

<div className="card">...</div> を選択してから:

@react.component
let make = (~items) => {
  <div className="container">
    <div className="card">
      {items->Array.map(item => <span key={item}> {React.string(item)} </span>)->React.array}
    </div>
  </div>
}
module Card = {
  @react.component
  let make = (~items) => {
    <div className="card">
      {items->Array.map(item => <span key={item}> {React.string(item)} </span>)->React.array}
    </div>
  }
}

@react.component
let make = (~items) => {
  <div className="container">
    <Card items />
  </div>
}

JSX から React コンポーネントを抽出するのは React 開発における一般的なリファクタリングです — この自動化は必要な props を検出し、適切に構造化されたモジュールを作成するため、手動でコードをコピーして props を引き回す手間を省きます。

JSON.t として貼り付け

Native

Edit > Paste as JSON.t を使用して、クリップボードの JSON を ReScript の JSON.t 値に変換します。

各 JSON 値を手動で ReScript コンストラクタでラップする代わりに、生の JSON をペーストして正しく型付けされた JSON.t 式を即座に取得できます。

コード生成

Native

Cmd+N(または Alt+Insert)を押して Generate メニューを開きます:

  • Generate Switch Arms — バリアント型のマッチアームを自動生成

  • Generate Module Type — モジュール実装からモジュール型のスケルトンを生成

  • Generate Make Function — レコード型からコンストラクタ関数を生成

  • Generate JSON Encoder/Decoder — 型から JSON エンコーダーとデコーダー関数を生成

  • Generate Record Value — 全フィールドにデフォルト値を設定したレコード値を生成

Switch Arms の生成

キャレットがバリアント型宣言の中にある場合、このアクションはコンストラクターごとに1つのアームを持つ switch 式を生成します。すべてのバリアントを手動で列挙することなく、網羅的なパターンマッチを記述できます。

型宣言内にキャレットを置いて Cmd+N(または Alt+Insert)を押し、Switch Arms を選択します。

type shape =
  | Circle(float)
  | Rectangle(float, float)
  | Triangle(float, float, float)
  | Point
type shape =
  | Circle(float)
  | Rectangle(float, float)
  | Triangle(float, float, float)
  | Point

switch value {
| Circle(_) => todo
| Rectangle(_) => todo
| Triangle(_) => todo
| Point => todo
}

ペイロードを持つコンストラクター(例: Circle(float))は生成されたアームで _ ワイルドカードを取得し、ペイロードのないコンストラクター(例: Point)は直接マッチします。各アームの todo を実際のロジックに置き換えてください。

Module Type の生成

キャレットがモジュール宣言の中にある場合、このアクションは module type シグネチャのスケルトンを生成し、モジュールの上に挿入します。生成されたシグネチャには、モジュール本体にあるすべての let, type, external、およびネストされた module 宣言が含まれます。

モジュール宣言内にキャレットを置いて Cmd+N(または Alt+Insert)を押し、Module Type を選択します。

module StringUtils = {
  type config = {verbose: bool}

  let capitalize = (s: string) => {
    // ...
  }

  let truncate = (s: string, maxLen: int) => {
    // ...
  }

  module Internal = {
    let helper = () => ()
  }
}
module type StringUtilsType = {
  type config
  let capitalize: 'a
  let truncate: 'a
  module Internal: {}
}

module StringUtils = {
  type config = {verbose: bool}

  let capitalize = (s: string) => {
    // ...
  }

  let truncate = (s: string, maxLen: int) => {
    // ...
  }

  module Internal = {
    let helper = () => ()
  }
}

生成された型は値の型のプレースホルダーとして 'a を使用します -- これらを実際の型シグネチャに置き換えてください。型宣言は定義本体なしで表示されるため、公開する型の形状を指定できます。ネストされたモジュールは空の {} シグネチャでリストされるため、内容を記入してください。

Make 関数の生成

キャレットがレコード型宣言の中にある場合、このアクションは各レコードフィールドに対応するラベル付き引数を持つ make コンストラクタ関数を生成します。

型宣言内にキャレットを置いて Cmd+N(または Alt+Insert)を押し、Make Function を選択します。

type user = {
  name: string,
  age: int,
  email: string,
}
type user = {
  name: string,
  age: int,
  email: string,
}

let make = (~name, ~age, ~email) => {
  name,
  age,
  email,
}

オプショナルフィールド(例: email?: string)はオプショナルラベル付き引数(~email=?)として生成されます。

JSON エンコーダー/デコーダーの生成

キャレットがレコード型またはバリアント型宣言の中にある場合、このアクションは @rescript/core の JSON モジュールを使用して JSON エンコーダーとデコーダー関数を生成します(外部依存は不要)。

型宣言内にキャレットを置いて Cmd+N(または Alt+Insert)を押し、JSON Encoder/Decoder を選択します。

レコード型の例:

type user = {name: string, age: int, email: option<string>}

各フィールドを適切な JSON.t コンストラクター(String、Number、Boolean、Null、Object、Array)に変換するエンコーダーと、JSON 構造をパターンマッチしてレコード型に戻すデコーダーを生成します。

バリアント型の例(単純な enum):

type color = Red | Green | Blue

各コンストラクターがその名前を JSON 文字列としてマッピングする String ベースのエンコーダー/デコーダーを生成します。

バリアント型の例(タグ付きユニオン):

type status = Success(string) | Error(int)

"tag" フィールドと位置ペイロードフィールド("_0"、"_1"、...)を持つ Object を使用したタグ付きユニオンのエンコーダー/デコーダーを生成します。

サポートされる型: string、int、float、bool、option<T>、array<T>、および任意のネスト(例: option<array<string>>)。認識されない型には /* TODO */ プレースホルダーが生成されるので、手動で記入してください。

命名規則: 関数名は encode + 型名の先頭大文字 と decode + 型名の先頭大文字(例: encodeUser / decodeUser)です。型名が t の場合は、単に encode / decode となります。

レコード値の生成

キャレットがレコード型宣言の中にある場合、このアクションは全フィールドにデフォルト値を設定したレコード値を生成します。初期値やテストフィクスチャの素早い作成に便利です。

型宣言内にキャレットを置いて Cmd+N(または Alt+Insert)を押し、Record Value を選択します。

type user = {
  name: string,
  age: int,
  active: bool,
  email: option<string>,
}
type user = {
  name: string,
  age: int,
  active: bool,
  email: option<string>,
}

let value: user = {
  name: "",
  age: 0,
  active: false,
  email: None,
}

デフォルト値はフィールドの型から推論されます: string には ""、int には 0、float には 0.0、bool には false、option<T> には None、array<T> には []。

モジュールタイプ実装の生成

キャレットが module type 宣言の中にある場合、このアクションは各シグネチャエントリに対するスタブ関数を持つモジュールタイプの実装モジュールを生成します。

モジュールタイプ宣言内にキャレットを置いて Cmd+N(または Alt+Insert)を押し、Module Type Implementation を選択します。

module type Printable = {
  type t
  let toString: t => string
  let print: t => unit
}
module type Printable = {
  type t
  let toString: t => string
  let print: t => unit
}

module PrintableImpl: Printable = {
  type t
  let toString = (_) => todo
  let print = (_) => todo
}

todo プレースホルダーを実際の実装に置き換えてください。生成されたモジュールはモジュールタイプに制約されているため、シグネチャの不足や不正をコンパイラが検出します。

コード生成は型定義を動作するコードに変換します — switch アーム、コンストラクタ、JSON コーデック、モジュールスケルトンが型から自動作成され、面倒でエラーの起きやすいボイラープレート記述を排除します。

末尾スペースの除去

Native

プラグインは IntelliJ が保存時に末尾スペースを削除する際、文字列リテラル内のスペースを保護します。この保護がないと、文字列行末の意図的なスペースが除去されてしまいます。

保護されるトークン型:

  • STRING_VALUE — 通常の文字列コンテンツ

  • JS_STRING_OPEN / JS_STRING_CLOSE — JavaScript テンプレート文字列の境界

末尾スペースの動作は Settings > Editor > General > On Save で設定できます。

この保護により、文字列リテラル内の意図的なスペースがエディタの末尾スペースクリーンアップで静かに削除されることがなく、文字列が多いコードでの微妙なバグを防ぎます。

エディタフローティングツールバー

Native

ReScript ファイルの編集時にフローティングツールバーが表示され、よく使うアクションに素早くアクセスできます:

  • Format — 現在のファイルをフォーマット(Cmd+Option+L)

  • Open Compiled JS — コンパイル済み JavaScript 出力を開く

  • Create Interface — .resi インターフェースファイルを生成

ツールバーは ReScript ファイルの編集開始時に自動表示され、使用していないときは自動的に非表示になります。

フローティングツールバーは最も一般的な ReScript 固有のアクション — フォーマット、コンパイル済み JS の表示、インターフェース作成 — をワンクリックで提供し、キーボードショートカットを覚える必要がありません。

スペルチェック

Native

プラグインは以下に対して IntelliJ の組み込みスペルチェッカーをサポートします:

  • コメント(行コメントとブロックコメント)

  • 文字列リテラル

  • 識別子(camelCase 分割)

組み込みのスペルチェックにより入力中にコメント、文字列、識別子のタイポをキャッチし、別途レビューステップなしでプロフェッショナルなコード品質を維持できます。

Backspace ハンドラー

Native

Backspace で開始 JSX タグを削除すると、対応する終了タグも自動的に削除されます。

ペアタグ削除により孤立した閉じタグを防ぎます — 開き JSX タグをバックスペースで削除すると、閉じタグも自動的に消え、マークアップのバランスが保たれます。

要素の左右移動

Native

Alt+Shift+Cmd+Left / Alt+Shift+Cmd+Right でカンマ区切りの要素を入れ替えます。関数の引数、配列の要素、レコードフィールド、タプルの要素に対応しています。

手動のカット&ペーストの代わりにキーボードショートカットで引数、配列項目、レコードフィールドを並べ替え、カンマとフォーマットが自動的に正しく保たれます。

コードブロックの選択

Native

Ctrl+Shift+[ と Ctrl+Shift+] を使用して、囲んでいるコードブロック(ブレース区切り)の先頭と末尾に移動します。

大きな関数本体や深くネストされた構造で作業する際に、スクロールや対応するブレースの検索なしでブロック境界に素早くジャンプできます。

リストの分割/結合

Native

カンマ区切りのリストを単一行と複数行の形式で切り替えます。Edit > Split/Join List から利用できます。

コンパクト形式と展開形式のリスト切り替えは単一のアクションで、改行やカンマを手動で追加・削除することなく可読性のためのコード密度を調整できます。

コピー/ペースト時のエスケープ

Native

文字列リテラルにテキストを貼り付けると、特殊文字(バックスラッシュ、引用符、改行、タブ)が自動的にエスケープされます。

自動エスケープにより、文字列リテラルに生テキストをペーストしても特殊文字が正しく処理されることが保証され、エスケープされていない引用符やバックスラッシュによる発見しにくい構文エラーを回避できます。

Unwrap/Remove(ラップ解除/削除)

Native

Ctrl+Shift+Delete(macOS では Cmd+Shift+Delete)を押して、囲んでいるラッパーを除去し、内側の式を抽出します。

カーソル位置で適用可能なすべてのラップ解除オプションがポップアップに表示されます。いずれかを選択してラップを解除します。

サポートされるラッパー

ラッパー

変更前

変更後

Some(...)

Some(myValue)

myValue

Ok(...)

Ok(result)

result

Error(...)

Error(msg)

msg

if (...) { ... }

if (cond) { body }

body

switch ... { ... }

switch x { | _ => body }

body

try { ... } catch { ... }

try { body } catch { | e => () }

body

{ ... }(ブロック)

{ expr }

expr

例:

let greeting = Some("Hello, world!")
let greeting = "Hello, world!"

Unwrap/Remove は Surround With の逆で、Some()、if、try などのラッパーをワンアクションで剥がし、デリミタを手動で削除して再インデントすることなく式を簡素化します。

JSX 自動閉じタグ

Native

JSX 開始タグを閉じるために > を入力すると、対応する終了タグが自動的に挿入され、カーソルはタグ間に配置されます。

<div> を入力:

<div>
<div></div>

以下に対応しています:

  • HTML 要素: <div>, <span>, <input>

  • React コンポーネント: <MyComponent>

  • モジュール修飾コンポーネント: <Module.Component>

自己閉じタグ(例: <br />)、コメント内、文字列リテラル内では自動閉じは動作しません。

自動閉じタグによりキーストロークを節約し、JSX タグの不一致を防ぎます — 開きタグを入力すると閉じタグが自動的に表示され、記述中のマークアップのバランスが保たれます。

Enter ハンドラー(コメント継続)

Native

コメント内で Enter を押すと、次の行に適切なコメント継続文字が自動的に挿入されます。

ドキュメントコメント

/** ... */ ブロック内で Enter を押すと、新しい行の先頭に * が挿入されます:

/** Some documentation|

Enter を押した後:

/** Some documentation
 * |

行コメント

// コメント内で Enter を押すと、新しい行の先頭に // が挿入されます:

// This is a comment|

Enter を押した後:

// This is a comment
// |

ドキュメントコメント(///)も継続されます:

/// A doc comment|

Enter を押した後:

/// A doc comment
/// |

コメント継続により、各行にプレフィックスを手動で入力することなく複数行コメントを適切にフォーマットし、クリーンなコメントスタイルを楽に維持できます。

スマート行結合

Native

Ctrl+Shift+J(macOS では Cmd+Shift+J)を押して、ReScript に適した方法で現在の行を次の行と結合します。

パイプチェーンの結合

行が -> で終わるか、次の行が -> で始まる場合、スペースを追加せずに行が結合されます:

value->
  Array.map(x => x + 1)
value->Array.map(x => x + 1)

Let バインディングの結合

行が = で終わる場合、= の後にスペース1つを入れて行が結合されます:

let result =
  computeValue()
let result = computeValue()

アロー関数の結合

行が => で終わる場合、スペース1つを入れて行が結合されます:

let fn = (x) =>
  x + 1
let fn = (x) => x + 1

上記のパターンに該当しない場合は、IDE の標準の行結合動作が使用されます。

スマート結合は ReScript 構文を理解します — パイプチェーンはスペースなしで結合し、let バインディングは = を保持し、アロー関数は可読性を維持するため、汎用的な行結合よりクリーンな結果を生成します。

Rename Variant Constructor(LSP 不要のバリアント constructor リネーム)

Native

標準の Shift+F6 リネームは言語サーバ上の textDocument/rename を経由するため、最も正確なクロスファイル書き換えが得られます。言語サーバが起動していない (node が PATH に無い、@rescript/language-server 未インストール、ネットワーク制限下の) 環境ではその経路が使えません。本 Alt+Enter intention は、どこでも動くトークン形ヒューリスティックのフォールバックを提供します。

起動方法: バリアント constructor として使われている UIDENT — | Foo(_) => のような switch arm pattern、type 宣言の | Foo arm、または constructor 呼び出し Foo(x) — に キャレットを置き、Alt+Enter を押して Rename variant constructor (project-wide, no LSP) を選択します。

仕組み

RescriptConstructorOccurrenceClassifier がプロジェクト内の各 UIDENT を分類します — CONSTRUCTOR / PATTERN / MODULE_QUALIFIED_TAIL / OTHER を、前後の non-trivia トークンを見て判定します:

周辺トークン

判定

| Foo / | Foo(_)

PATTERN (switch arm または type arm)

Module.Foo

MODULE_QUALIFIED_TAIL (Foo 部分のみ書き換え)

Foo(x)

CONSTRUCTOR (constructor 呼び出し)

let x = Foo / [Foo, …] / f(Foo)

CONSTRUCTOR (式位置の 0-ary constructor)

<Foo /> / : Foo / module Foo = …

OTHER (対象外)

文字列リテラル / コメント内のトークン

OTHER (レキサーが除外)

続いて RescriptConstructorOccurrenceFinder が、プロジェクト内の .res / .resi ファイルに対して PsiSearchHelper.processElementsWithWord を走らせ、各ヒットを classifier に通して CONSTRUCTOR / PATTERN / MODULE_QUALIFIED_TAIL のものだけを残します。上限は 500 件で、超過した場合は intention が「Shift+F6 (LSP rename) を使うか、対象を絞ってください」とエラーを出して中止するので、巨大な diff を誤って生成することはありません。

実際の書き換えは単一の WriteCommandAction で行われるため、プロジェクト全体の変更が 1 ステップで Undo されます。

制限事項

  • classifier は純粋に構文ベースです。同名 constructor を持つ別バリアント (例: type a = | Foo と type b = | Foo) はまとめてリネームされてしまうので、型による区別が必要な場合は Shift+F6 (LSP rename) を使ってください。

  • ポリモーフィックバリアント (#foo) はこの intention の対象外です。

  • モジュール修飾された呼び出し箇所は末尾のみが書き換えられ、先頭の Module. 部分は触れられません。

JSX 開閉タグペアのハイライト

Native

JSX タグ名(開きタグ・閉じタグのどちらでも)にカーソルを置くと、要素の反対側にある対応するタグ名がハイライトされ、深くネストしたマークアップでも要素の境界が一目で分かります。

例:

// Place caret on either "div": both the opening and closing tag names highlight
<div>
  <span> {React.string("hi")} </span>
</div>

閉じられていない要素(閉じタグがまだない場合)では開きタグ名のみがハイライトされます。JSX フラグメント(<>...</>)にはタグ名がないため何もハイライトされません。同名のタグがネストしている場合は、カーソルを含む要素のペアに解決されます。

ペアタグハイライトにより JSX 要素がどこで開きどこで閉じるかが一目で分かります — タグ名にカーソルを置けば、同名のタグが複数ネストしていても、その対応するタグが即座に分かります。

JSX 開閉タグの同期リネーム

Native

JSX タグ名を編集すると、その変更が要素の反対側にある対応タグへ即座に反映され、開きタグと閉じタグの名前がずれることがありません。<div> で文字を入力・削除すると末尾の </div> がその場で追従し、同期された編集全体が 1 ステップで Undo できます。

例:

// Caret right after "div" in the opening tag; type "x"
<div></div>
// Result — both names update together
<divx></divx>

ミラーリングは 2 つの名前がまだ一致している間(キー入力前に編集中の側が反対側と一致していた場合)にのみ発火するため、意図的に別名にした閉じタグを上書きすることはありません。同期する 2 つ目の名前を持たない自己終了タグ(<br />)やフラグメント(<>...</>)では何も行いません。

同期リネームは、開きタグを変更した後に閉じタグを手作業で直す手間をなくします。その場でリネームすれば対応する側が追従し、1 回の Undo ですべて元に戻せます。

ワード選択(拡大/縮小)

Native

Ctrl+W(macOS では Alt+Up)で選択を拡大、Ctrl+Shift+W(macOS では Alt+Down)で選択を縮小します。ReScript に適した境界を認識します。

選択境界

ワードセレクターは選択の拡大/縮小に対して以下の ReScript 固有の境界を認識します:

コンテキスト

選択の拡大先

文字列リテラル内

文字列の内容(引用符なし) → 文字列全体(引用符を含む)

括弧 (...) 内

括弧内の内容 → 括弧を含む全体

ブロックコメント /* ... */ 内

コメント内容 → デリミタを含むコメント全体

行コメント // ... 内

コメントテキスト → コメント行全体

ReScript のコード構造を扱う際に、デフォルトのワードセレクターよりも自然な選択動作を提供します。

ReScript 対応の選択境界により、標準の拡大/縮小ショートカットを使って、引用符なしの文字列内容やデリミタなしのブロックコメントテキストなど、必要なコンテンツを正確に選択できます。

JSX として貼り付け

Native

HTML コンテンツを ReScript ファイルに貼り付けると、自動的に JSX 構文に変換されます:

  • HTML 属性(class、for、onclick)が JSX の同等属性(className、htmlFor、onClick)にリネームされます

  • Void 要素(<br>、<img>、<input>)が自己閉じタグ(<br />)に変換されます

  • インライン style 文字列が ReScript のスタイルオブジェクトに変換されます

  • Boolean 属性(例: disabled、checked)が JSX の boolean props として保持されます

  • data-* および aria-* 属性はそのまま保持されます

Paste as JSX は HTML を ReScript JSX に自動変換します — class を className に手動でリネームしたり void 要素を自己終了させたりする代わりに、ペースト時に変換が行われます。

ReScript として貼り付け

Native

この変換は、標準のペーストショートカット(Cmd+V / Ctrl+V)で JavaScript または TypeScript コードを .res ファイルに貼り付けると自動的にトリガーされます。別途メニューアクションは不要です — プラグインがクリップボード内の JavaScript/TypeScript パターンを検出し、その場で変換します。

JavaScript または TypeScript コードを ReScript ファイルに貼り付けると、自動的に ReScript 構文に変換されます:

JavaScript の変換

  • const/let/var 宣言が let バインディングに変換されます

  • アロー関数 (x) => { return x } が (x) => x に簡素化されます

  • === / !== が == / != に変換されます

  • console.log(x) が Js.log(x) に変換されます

  • null / undefined が None に変換されます

  • テンプレートリテラルはそのまま維持されます(ReScript は同じ構文を使用)

TypeScript 型の除去

  • 変数の型注釈(const x: string = ...)が除去されます

  • 関数パラメータの型注釈((a: number, b: string))が除去されます

  • 戻り値の型注釈(): boolean {)が除去されます

  • 型アサーション(value as string)が除去されます

  • interface および enum 宣言がコメントアウトされます

  • export type / export interface / export enum がコメントアウトされます

JSX/TSX パターンの変換

  • 条件付きレンダリング {condition && <expr>} が {condition ? <expr> : React.null} に変換されます

  • 配列メソッド(.map()、.filter()、.forEach())がパイプファーストスタイル(->Array.map())に変換されます

  • JSX スプレッド {...props} に警告コメントが追加されます(ReScript JSX ではサポートされていません)

const greeting = (name: string): string => {
  console.log("Hello, " + name);
  return name.toUpperCase();
}
let greeting = (name) => {
  Js.log("Hello, " ++ name)
  name->String.toUpperCase
}

Paste as ReScript は JavaScript/TypeScript と ReScript のギャップを埋めます — ドキュメント、Stack Overflow、既存の JS/TS ファイルからコードをコピーし、自動構文変換付きで .res ファイルに直接ペーストできます。

React JSX/TSX コード(className=、{expression} ブレース、onClick= などの camelCase イベントハンドラを含む)は、HTML→JSX コンバータではなく JS/TS→ReScript コンバータによって処理され、JSX パターンが正しく扱われます。