///|
fn main {
let args = @env.args()
let command = if args.length() > 1 { args[1] } else { "help" }
match command {
"inspect" => run_inspect(args)
"lookup" => run_lookup(args)
"reverse" => run_reverse(args)
"reverse-all" => run_reverse_all(args)
"wasm-url" => run_wasm_url(args)
"wasm-set-url" => run_wasm_set_url(args)
"wasm-remove-url" => run_wasm_remove_url(args)
"demo" => {
let output = run_demo() catch {
error => {
fail(error.to_string())
""
}
}
println(output)
}
"version" => println("moonbit-sourcemap 0.1.0")
"help" | "--help" | "-h" => usage() |> println
_ => fail("unknown command '\{command}'\n\n\{usage()}")
}
}
///|
fn usage() -> String {
(
#|moonbit-sourcemap - inspect Source Map v3 files
#|
#|Usage:
#| moon run cmd/main -- inspect
#| moon run cmd/main -- lookup
#| moon run cmd/main -- reverse
#| moon run cmd/main -- reverse-all
#| moon run cmd/main -- wasm-url
#| moon run cmd/main -- wasm-set-url
#| moon run cmd/main -- wasm-remove-url
#| moon run cmd/main -- demo
#| moon run cmd/main -- version
)
}
///|
fn fail(message : String) -> Unit {
println("error: \{message}")
abort("moonbit-sourcemap: \{message}")
}
///|
fn read_or_fail(path : String) -> String {
match read_file(path) {
Some(content) => content
None => {
fail("cannot read '\{path}'")
""
}
}
}
///|
fn read_binary_or_fail(path : String) -> Bytes {
match read_binary(path) {
Some(content) => content
None => {
fail("cannot read '\{path}'")
b""
}
}
}
///|
fn write_binary_or_fail(path : String, content : Bytes) -> Unit {
if !write_binary(path, content) {
fail("cannot write '\{path}'")
}
}
///|
fn parse_int_or_fail(value : String, label : String) -> Int {
@string.parse_int(value) catch {
_ => {
fail("\{label} must be an integer, got '\{value}'")
0
}
}
}
///|
fn run_inspect(args : Array[String]) -> Unit {
if args.length() != 3 {
fail("usage: moon run cmd/main -- inspect ")
}
let output = inspect_document(read_or_fail(args[2])) catch {
error => {
fail(error.to_string())
""
}
}
println(output)
}
///|
fn run_lookup(args : Array[String]) -> Unit {
if args.length() != 5 {
fail("usage: moon run cmd/main -- lookup ")
}
let line = parse_int_or_fail(args[3], "line")
let column = parse_int_or_fail(args[4], "column")
let output = lookup_document(read_or_fail(args[2]), line, column) catch {
error => {
fail(error.to_string())
""
}
}
println(output)
}
///|
fn run_reverse(args : Array[String]) -> Unit {
if args.length() != 6 {
fail(
"usage: moon run cmd/main -- reverse ",
)
}
let line = parse_int_or_fail(args[4], "line")
let column = parse_int_or_fail(args[5], "column")
let output = reverse_document(read_or_fail(args[2]), args[3], line, column) catch {
error => {
fail(error.to_string())
""
}
}
println(output)
}
///|
fn run_reverse_all(args : Array[String]) -> Unit {
if args.length() != 6 {
fail(
"usage: moon run cmd/main -- reverse-all ",
)
}
let line = parse_int_or_fail(args[4], "line")
let column = parse_int_or_fail(args[5], "column")
let output = reverse_all_document(
read_or_fail(args[2]),
args[3],
line,
column,
) catch {
error => {
fail(error.to_string())
""
}
}
println(output)
}
///|
fn run_wasm_url(args : Array[String]) -> Unit {
if args.length() != 3 {
fail("usage: moon run cmd/main -- wasm-url ")
}
let output = wasm_url_document(read_binary_or_fail(args[2])) catch {
error => {
fail(error.to_string())
""
}
}
println(output)
}
///|
fn run_wasm_set_url(args : Array[String]) -> Unit {
if args.length() != 5 {
fail(
"usage: moon run cmd/main -- wasm-set-url ",
)
}
let output = @sourcemap.wasm_set_source_mapping_url(
read_binary_or_fail(args[2]),
args[3],
) catch {
error => {
fail(error.to_string())
b""
}
}
write_binary_or_fail(args[4], output)
println(args[3])
}
///|
fn run_wasm_remove_url(args : Array[String]) -> Unit {
if args.length() != 4 {
fail(
"usage: moon run cmd/main -- wasm-remove-url ",
)
}
let output = @sourcemap.wasm_remove_source_mapping_url(
read_binary_or_fail(args[2]),
) catch {
error => {
fail(error.to_string())
b""
}
}
write_binary_or_fail(args[3], output)
println("removed")
}
///|
pub fn wasm_url_document(
input : Bytes,
) -> String raise @sourcemap.SourceMapError {
match @sourcemap.wasm_source_mapping_url(input) {
Some(url) => url
None => "no sourceMappingURL"
}
}
///|
pub fn inspect_document(
input : String,
) -> String raise @sourcemap.SourceMapError {
let map = @sourcemap.parse_json(input)
let file = match map.file {
Some(value) => value
None => "(none)"
}
"file: \{file}\nsources: \{map.sources.length()}\nnames: \{map.names.length()}\nmappings: \{map.mappings.length()}"
}
///|
pub fn lookup_document(
input : String,
line : Int,
column : Int,
) -> String raise @sourcemap.SourceMapError {
if line < 0 || column < 0 {
return "no mapping"
}
let map = @sourcemap.parse_json(input)
match map.original_position_for(line, column) {
None => "no mapping"
Some(position) =>
match
(position.source, position.original_line, position.original_column) {
(Some(source), Some(original_line), Some(original_column)) => {
let name = match position.name {
Some(value) => " name=\{value}"
None => ""
}
"\{source}:\{original_line}:\{original_column}\{name}"
}
_ => "unmapped"
}
}
}
///|
pub fn reverse_document(
input : String,
source : String,
line : Int,
column : Int,
) -> String raise @sourcemap.SourceMapError {
if line < 0 || column < 0 {
return "no mapping"
}
let map = @sourcemap.parse_json(input)
match map.generated_position_for(source, line, column) {
None => "no mapping"
Some(position) => {
let file = match map.file {
Some(value) => value
None => "(generated)"
}
"\{file}:\{position.generated_line}:\{position.generated_column}"
}
}
}
///|
pub fn reverse_all_document(
input : String,
source : String,
line : Int,
column : Int,
) -> String raise @sourcemap.SourceMapError {
let map = @sourcemap.parse_json(input)
let positions = map.generated_positions_for(source, line, column)
if positions.length() == 0 {
return "no mapping"
}
let file = match map.file {
Some(value) => value
None => "(generated)"
}
let mut output = ""
for i in 0.. 0 {
output = output + "\n"
}
let position = positions[i]
output = output +
"\{file}:\{position.generated_line}:\{position.generated_column}"
}
output
}
///|
fn run_demo() -> String raise @sourcemap.SourceMapError {
let builder = @sourcemap.SourceMapBuilder::new()
builder.add_mapping(0, 0, "src/main.mbt", 4, 2, name=Some("main"))
builder.add_mapping(0, 12, "src/main.mbt", 5, 4)
let map = builder.build(file=Some("app.wasm"))
"mappings: \{map.encode_mappings()}\n" + lookup_document(map.to_json(), 0, 14)
}