Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ component boundary も提供します。評価済みの `use_tea` result を
recharts = ["PieChart", "Pie"]
```

Glendix はこの設定を標準 TOML として解析します。パッケージマネージャー、
互換モード、モジュール名、コンポーネント名は引用符付き TOML 文字列にし、
各バインディング値は 1 個の文字列または文字列配列にする必要があります。
不正な TOML、重複キー、引用符のない文字列風の値は部分的に解釈せずエラーに
なります。`gleam.toml` または Glendix テーブルがない場合は、従来どおり
override とバインディングが未設定として扱われます。

```gleam
import gleam/result
import glendix/binding
Expand Down
6 changes: 6 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ component 경계도 만든다. 이미 평가된 `use_tea` 결과를 `redraw.keye
recharts = ["PieChart", "Pie"]
```

Glendix는 이 설정을 표준 TOML로 해석한다. 패키지 매니저, 호환 모드, 모듈 및
컴포넌트 이름은 따옴표로 감싼 TOML 문자열이어야 하며, 각 바인딩 값은 문자열
하나 또는 문자열 배열이어야 한다. 잘못된 TOML, 중복 키, 따옴표 없는 문자열
형태의 값은 일부만 해석하지 않고 오류로 처리한다. `gleam.toml` 또는 Glendix
테이블이 없으면 기존처럼 override와 바인딩이 없는 것으로 처리한다.

```gleam
import gleam/result
import glendix/binding
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ recharts = ["PieChart", "Pie"]
Install the npm package, then run `gleam run -m glendix/install`. Glendix owns
both component lookup and element construction; Mendraw is not required:

Glendix parses this configuration as standard TOML. Package-manager,
compatibility, module, and component names must be quoted TOML strings, and
each binding value must be either one string or an array of strings. Malformed
TOML, duplicate keys, and unquoted string-like values are rejected instead of
being partially interpreted. A missing `gleam.toml` or missing Glendix table
still means that no override or bindings are configured.

```gleam
import gleam/result
import glendix/binding
Expand Down
1 change: 1 addition & 0 deletions gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ lustre = ">= 5.7.1 and < 6.0.0"
mendraw = ">= 2.0.0 and < 3.0.0"
simplifile = ">= 2.6.0 and < 3.0.0"
xmlm = ">= 1.0.1 and < 2.0.0"
tom = ">= 2.1.0 and < 3.0.0"

[dev_dependencies]
gleeunit = ">= 1.11.0 and < 2.0.0"
3 changes: 3 additions & 0 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ packages = [
{ name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
{ name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" },
{ name = "gleam_stdlib", version = "1.0.3", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1F543AFBA5D33DA493E6087F4E4C4F20D899411343512686C98A8ABB2963CF22" },
{ name = "gleam_time", version = "1.10.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "56539216E4C4B1748714652AB38F0BD16B9101F61DB62769FDC7CD42A8E5E833" },
{ name = "gleeunit", version = "1.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "EC31ABA74256AEA531EDF8169931D775BBB384FED0A8A1BDC4DD9354E3E21826" },
{ name = "houdini", version = "1.2.1", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "6F8AC2F12974567FB744BEA66AC93CEB76AAEA19AD28564623F76CDA9BC26A85" },
{ name = "lustre", version = "5.7.1", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "663A2D1A3458914CA537A42AC07E601DD3FD85415EBDAF4717F2DFF6E86F90F9" },
{ name = "mendraw", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "redraw", "redraw_dom"], otp_app = "mendraw", source = "hex", outer_checksum = "BB913054A5FEDC872AAB114FFADDFB791DACFE605B3DCEEAD3620F11BB59D090" },
{ name = "redraw", version = "19.2.2", build_tools = ["gleam"], requirements = ["gleam_javascript", "gleam_stdlib"], otp_app = "redraw", source = "hex", outer_checksum = "B8CEEB74E8846CE10B8360B924DAD22441B61D947F9449854164F0686C4B8661" },
{ name = "redraw_dom", version = "19.2.2", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_stdlib", "redraw"], otp_app = "redraw_dom", source = "hex", outer_checksum = "80278296AD6E3D4457D6FF6A14FEA3E90696284BEA297BDE10E430FC4CE726B8" },
{ name = "simplifile", version = "2.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "A2727627B063E87351934C7F7F008F2D1FDB16F6DE0B8C79F9E46459CFC9C164" },
{ name = "tom", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "DCF04CB7AB35D58CFC598C66EA2E1816D160759802C89B2BA6238780D59BC256" },
{ name = "xmlm", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "xmlm", source = "hex", outer_checksum = "F23155B6F0B22CB8E09DAD41BB6B1CD036725FD0A80EE25B1D1B14138683A81D" },
]

Expand All @@ -38,4 +40,5 @@ mendraw = { version = ">= 2.0.0 and < 3.0.0" }
redraw = { version = ">= 19.2.2 and < 20.0.0" }
redraw_dom = { version = ">= 19.2.2 and < 20.0.0" }
simplifile = { version = ">= 2.6.0 and < 3.0.0" }
tom = { version = ">= 2.1.0 and < 3.0.0" }
xmlm = { version = ">= 1.0.1 and < 2.0.0" }
177 changes: 130 additions & 47 deletions src/glendix/cmd.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import gleam/io
import gleam/option
import gleam/result
import glendix/configuration

/// Describes a JavaScript tooling failure.
pub type CommandError {
Expand All @@ -19,18 +20,10 @@ pub fn exec(command command: String) -> Result(Nil, CommandError) {

/// Detects the configured or lockfile-selected JavaScript package manager.
pub fn detect_package_manager() -> Result(String, CommandError) {
use override <- result.try(
read_pm_override()
|> map_raw_error("read package-manager override"),
)
case override {
option.Some(name) ->
name
|> parse_package_manager
|> result.map(package_manager_name)
option.None ->
Ok(package_manager_name(detect_package_manager_from_lockfile()))
}
use project_configuration <- result.try(read_configuration(
"read package-manager override",
))
detect_package_manager_with(project_configuration)
}

/// Detects the package-manager command used to run JavaScript tools.
Expand Down Expand Up @@ -58,54 +51,94 @@ pub fn package_manager_commands(

/// Runs Pluggable Widgets Tools with the supplied arguments.
pub fn run_tool(args args: String) -> Result(Nil, CommandError) {
use package_manager <- result.try(detect_package_manager())
use experimental_native <- result.try(read_experimental_native_mode())
case experimental_native {
True ->
use project_configuration <- result.try(read_configuration(
"read tool configuration",
))
use package_manager <- result.try(detect_package_manager_with(
project_configuration,
))
use compatibility <- result.try(read_compatibility(project_configuration))
case compatibility {
configuration.ExperimentalNative ->
run_experimental_native_raw(package_manager, args)
|> map_raw_error("run experimental-native tool")
False -> {
use runner <- result.try(detect_runner())
configuration.Standard -> {
use runner <- result.try(
package_manager
|> parse_package_manager
|> result.map(package_manager_runner),
)
exec(runner <> " pluggable-widgets-tools " <> args)
}
}
}

/// Runs Pluggable Widgets Tools through the Glendix bridge.
pub fn run_tool_with_bridge(args args: String) -> Result(Nil, CommandError) {
use package_manager <- result.try(detect_package_manager())
use experimental_native <- result.try(read_experimental_native_mode())
case experimental_native {
True ->
run_experimental_native_with_bridge_raw(package_manager, args)
use project_configuration <- result.try(read_configuration(
"read tool configuration",
))
use package_manager <- result.try(detect_package_manager_with(
project_configuration,
))
use compatibility <- result.try(read_compatibility(project_configuration))
use bindings <- result.try(read_bindings(project_configuration))
case compatibility {
configuration.ExperimentalNative ->
run_experimental_native_with_bridge_raw(package_manager, args, bindings)
|> map_raw_error("run experimental-native tool with bridge")
False -> {
use runner <- result.try(detect_runner())
run_with_bridge(runner <> " pluggable-widgets-tools " <> args)
configuration.Standard -> {
use runner <- result.try(
package_manager
|> parse_package_manager
|> result.map(package_manager_runner),
)
run_with_bridge(runner <> " pluggable-widgets-tools " <> args, bindings)
|> map_raw_error("run tool with bridge")
}
}
}

/// Runs the web build in development mode through the Glendix bridge.
pub fn run_tool_dev() -> Result(Nil, CommandError) {
use package_manager <- result.try(detect_package_manager())
use experimental_native <- result.try(read_experimental_native_mode())
case experimental_native {
True ->
run_experimental_native_dev_with_bridge_raw(package_manager, "build:web")
use project_configuration <- result.try(read_configuration(
"read tool configuration",
))
use package_manager <- result.try(detect_package_manager_with(
project_configuration,
))
use compatibility <- result.try(read_compatibility(project_configuration))
use bindings <- result.try(read_bindings(project_configuration))
case compatibility {
configuration.ExperimentalNative ->
run_experimental_native_dev_with_bridge_raw(
package_manager,
"build:web",
bindings,
)
|> map_raw_error("run experimental-native development tool with bridge")
False -> {
use runner <- result.try(detect_runner())
run_dev_with_bridge(runner <> " pluggable-widgets-tools build:web")
configuration.Standard -> {
use runner <- result.try(
package_manager
|> parse_package_manager
|> result.map(package_manager_runner),
)
run_dev_with_bridge(
runner <> " pluggable-widgets-tools build:web",
bindings,
)
|> map_raw_error("run development tool with bridge")
}
}
}

/// Generates Mendix widget bindings.
pub fn generate_bindings() -> Result(Nil, CommandError) {
generate_bindings_raw()
use project_configuration <- result.try(read_configuration(
"generate JavaScript bindings",
))
use bindings <- result.try(read_bindings(project_configuration))
generate_bindings_raw(bindings)
|> map_raw_error("generate JavaScript bindings")
}

Expand All @@ -131,6 +164,23 @@ type PackageManager {
Deno
}

fn detect_package_manager_with(
project_configuration: configuration.Configuration,
) -> Result(String, CommandError) {
use override <- result.try(
configuration.package_manager(project_configuration)
|> map_configuration_error("read package-manager override"),
)
case override {
option.Some(name) ->
name
|> parse_package_manager
|> result.map(package_manager_name)
option.None ->
Ok(package_manager_name(detect_package_manager_from_lockfile()))
}
}

fn parse_package_manager(name: String) -> Result(PackageManager, CommandError) {
case name {
"npm" -> Ok(Npm)
Expand Down Expand Up @@ -198,9 +248,25 @@ fn detect_package_manager_from_lockfile() -> PackageManager {
}
}

fn read_experimental_native_mode() -> Result(Bool, CommandError) {
read_experimental_native_mode_raw()
|> map_raw_error("read compatibility mode")
fn read_configuration(
operation: String,
) -> Result(configuration.Configuration, CommandError) {
configuration.read()
|> map_configuration_error(operation)
}

fn read_compatibility(
project_configuration: configuration.Configuration,
) -> Result(configuration.Compatibility, CommandError) {
configuration.compatibility(project_configuration)
|> map_configuration_error("read compatibility mode")
}

fn read_bindings(
project_configuration: configuration.Configuration,
) -> Result(List(#(String, List(String))), CommandError) {
configuration.bindings(project_configuration)
|> map_configuration_error("read binding configuration")
}

fn map_raw_error(
Expand All @@ -216,27 +282,42 @@ fn map_raw_error(
})
}

fn map_configuration_error(
configuration_result: Result(value, configuration.ConfigurationError),
operation: String,
) -> Result(value, CommandError) {
configuration_result
|> result.map_error(fn(error) {
CommandFailed(
operation: operation,
reason: configuration.error_message(error),
)
})
}

// -- FFI --
@external(javascript, "./cmd_ffi.mjs", "exec")
fn exec_raw(command command: String) -> Result(Nil, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "file_exists")
fn file_exists(path: String) -> Bool

@external(javascript, "./cmd_ffi.mjs", "read_pm_override")
fn read_pm_override() -> Result(option.Option(String), RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "read_experimental_native_mode")
fn read_experimental_native_mode_raw() -> Result(Bool, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "run_with_bridge")
fn run_with_bridge(command: String) -> Result(Nil, RawCommandError)
fn run_with_bridge(
command: String,
bindings: List(#(String, List(String))),
) -> Result(Nil, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "run_dev_with_bridge")
fn run_dev_with_bridge(build_command: String) -> Result(Nil, RawCommandError)
fn run_dev_with_bridge(
build_command: String,
bindings: List(#(String, List(String))),
) -> Result(Nil, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "generate_bindings")
fn generate_bindings_raw() -> Result(Nil, RawCommandError)
fn generate_bindings_raw(
bindings: List(#(String, List(String))),
) -> Result(Nil, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "run_experimental_native")
fn run_experimental_native_raw(
Expand All @@ -248,12 +329,14 @@ fn run_experimental_native_raw(
fn run_experimental_native_with_bridge_raw(
package_manager: String,
args: String,
bindings: List(#(String, List(String))),
) -> Result(Nil, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "run_experimental_native_dev_with_bridge")
fn run_experimental_native_dev_with_bridge_raw(
package_manager: String,
args: String,
bindings: List(#(String, List(String))),
) -> Result(Nil, RawCommandError)

@external(javascript, "./cmd_ffi.mjs", "command_error_message")
Expand Down
Loading
Loading