Revert "Add Decodal formatter"

This reverts commit 22f6bc1ab9.
This commit is contained in:
2026-07-09 17:46:24 +09:00
parent 22f6bc1ab9
commit ac99c4cb4e
16 changed files with 24 additions and 606 deletions
+5 -32
View File
@@ -6,7 +6,7 @@ use std::{
use decodal::{
Data, Diagnostic, DiagnosticKind, Engine, LoadedSource, SourceId, SourceLoader, Span,
format_diagnostic_with, format_source_with_source_id,
format_diagnostic_with,
};
fn main() -> ExitCode {
@@ -38,17 +38,6 @@ fn run() -> Result<(), String> {
println!("ok");
Ok(())
}
"fmt" | "format" => {
let next = args.next().unwrap_or_else(|| String::from("-"));
if next == "--write" || next == "-w" {
let path = args
.next()
.ok_or_else(|| String::from("missing file path for `decodal fmt --write`"))?;
format_path(&path, true)
} else {
format_path(&next, false)
}
}
"eval" | "materialize" => {
let path = args.next().unwrap_or_else(|| String::from("-"));
let data = materialize_path(&path)?;
@@ -65,21 +54,6 @@ fn run() -> Result<(), String> {
}
}
fn format_path(path: &str, write: bool) -> Result<(), String> {
if write && path == "-" {
return Err(String::from("cannot use --write with stdin"));
}
let root = read_root_source(path).map_err(format_raw_diagnostic)?;
let formatted = format_source_with_source_id(SourceId(0), &root.source)
.map_err(|error| format_diagnostic_with_root(&error, &root.name))?;
if write {
fs::write(path, formatted).map_err(|error| format!("failed to write `{path}`: {error}"))?;
} else {
print!("{formatted}");
}
Ok(())
}
fn materialize_path(path: &str) -> Result<Data, String> {
let root = read_root_source(path).map_err(format_raw_diagnostic)?;
let root_name = root.name.clone();
@@ -169,11 +143,10 @@ fn print_help() {
println!("Decodal - Deferred Constraint Data Language");
println!();
println!("Usage:");
println!(" decodal <file.dcdl> Materialize a DCDL file");
println!(" decodal eval <file.dcdl> Materialize a DCDL file");
println!(" decodal check <file.dcdl> Evaluate and materialize without printing data");
println!(" decodal fmt [--write] <file.dcdl> Format a DCDL file");
println!(" decodal - Read DCDL source from stdin");
println!(" decodal <file.dcdl> Materialize a DCDL file");
println!(" decodal eval <file.dcdl> Materialize a DCDL file");
println!(" decodal check <file.dcdl> Evaluate and materialize without printing data");
println!(" decodal - Read DCDL source from stdin");
}
fn format_diagnostic_with_root(error: &Diagnostic, root_name: &str) -> String {
-442
View File
@@ -1,442 +0,0 @@
use alloc::string::{String, ToString};
use core::fmt::Write;
use crate::{
Ast, Diagnostic, Expr, ExprId, Field, Literal, Param, SourceForm, Span,
ast::{BinaryOp, CompareOp, MatchArm, UnaryOp},
diagnostic::Result,
parse_source_with_source_id,
span::SourceId,
};
const INDENT: usize = 4;
pub fn format_source(source: &str) -> Result<String> {
format_source_with_source_id(SourceId(0), source)
}
pub fn format_source_with_source_id(source_id: SourceId, source: &str) -> Result<String> {
reject_comments(source_id, source)?;
let parsed = parse_source_with_source_id(source_id, source)?;
Ok(Formatter::new(&parsed.ast).format_root(parsed.root, parsed.source_form))
}
struct Formatter<'a> {
ast: &'a Ast,
}
impl<'a> Formatter<'a> {
fn new(ast: &'a Ast) -> Self {
Self { ast }
}
fn format_root(&self, root: ExprId, source_form: SourceForm) -> String {
let mut out = String::new();
match source_form {
SourceForm::Fields => {
if let Expr::Object(fields) = &self.ast.get(root).expr {
self.write_fields(&mut out, fields, 0);
} else {
self.write_expr(&mut out, root, 0, 0);
}
}
SourceForm::Expr => self.write_expr(&mut out, root, 0, 0),
}
if !out.ends_with('\n') {
out.push('\n');
}
out
}
fn write_expr(&self, out: &mut String, id: ExprId, indent: usize, parent_prec: u8) {
let expr = &self.ast.get(id).expr;
let prec = expr_prec(expr);
let paren = prec < parent_prec;
if paren {
out.push('(');
}
match expr {
Expr::Literal(literal) => self.write_literal(out, literal),
Expr::Ident(name) => out.push_str(name),
Expr::Object(fields) => self.write_object(out, fields, indent),
Expr::Array(items) => self.write_array(out, items, indent),
Expr::Let { bindings, body } => self.write_let(out, bindings, *body, indent),
Expr::Import(path) => {
out.push_str("import ");
write_quoted(out, path);
}
Expr::Path { base, field } => {
self.write_expr(out, *base, indent, prec);
out.push('.');
out.push_str(field);
}
Expr::Call { callee, args } => {
self.write_expr(out, *callee, indent, prec);
out.push('(');
for (index, arg) in args.iter().enumerate() {
if index > 0 {
out.push_str(", ");
}
self.write_expr(out, *arg, indent, 0);
}
out.push(')');
}
Expr::Function { params, body } => self.write_function(out, params, *body, indent),
Expr::Match { scrutinee, arms } => self.write_match(out, *scrutinee, arms, indent),
Expr::Unary { op, expr } => {
out.push_str(match op {
UnaryOp::Neg => "-",
UnaryOp::Not => "!",
});
self.write_expr(out, *expr, indent, prec);
}
Expr::Binary { op, lhs, rhs } => {
self.write_expr(out, *lhs, indent, prec);
out.push(' ');
out.push_str(binary_op_text(*op));
out.push(' ');
self.write_expr(out, *rhs, indent, prec + 1);
}
Expr::Default { base, fallback } => {
self.write_expr(out, *base, indent, prec);
out.push_str(" default ");
self.write_expr(out, *fallback, indent, prec + 1);
}
Expr::CompareConstraint { op, value } => {
out.push_str(compare_op_text(*op));
out.push(' ');
self.write_expr(out, *value, indent, prec);
}
Expr::RegexConstraint(pattern) => {
out.push('/');
out.push_str(pattern);
out.push('/');
}
Expr::Wildcard => out.push('_'),
}
if paren {
out.push(')');
}
}
fn write_literal(&self, out: &mut String, literal: &Literal) {
match literal {
Literal::String(value) => write_quoted(out, value),
Literal::Int(value) => {
let _ = write!(out, "{value}");
}
Literal::Float(value) => {
let text = value.to_string();
out.push_str(&text);
if !text.contains('.') && !text.contains('e') && !text.contains('E') {
out.push_str(".0");
}
}
Literal::Bool(value) => out.push_str(if *value { "true" } else { "false" }),
}
}
fn write_object(&self, out: &mut String, fields: &[Field], indent: usize) {
if fields.is_empty() {
out.push_str("{}");
return;
}
out.push('{');
out.push('\n');
self.write_fields(out, fields, indent + INDENT);
write_indent(out, indent);
out.push('}');
}
fn write_fields(&self, out: &mut String, fields: &[Field], indent: usize) {
for field in fields {
write_indent(out, indent);
self.write_field(out, field, indent);
out.push_str(";\n");
}
}
fn write_field(&self, out: &mut String, field: &Field, indent: usize) {
for (index, part) in field.path.iter().enumerate() {
if index > 0 {
out.push('.');
}
out.push_str(part);
}
out.push_str(" = ");
self.write_expr(out, field.value, indent, 0);
}
fn write_array(&self, out: &mut String, items: &[ExprId], indent: usize) {
if items.is_empty() {
out.push_str("[]");
return;
}
if items.iter().all(|item| self.is_inline(*item)) {
out.push('[');
for (index, item) in items.iter().enumerate() {
if index > 0 {
out.push_str(", ");
}
self.write_expr(out, *item, indent, 0);
}
out.push(']');
return;
}
out.push('[');
out.push('\n');
for item in items {
write_indent(out, indent + INDENT);
self.write_expr(out, *item, indent + INDENT, 0);
out.push_str(",\n");
}
write_indent(out, indent);
out.push(']');
}
fn write_let(&self, out: &mut String, bindings: &[Field], body: ExprId, indent: usize) {
out.push_str("let");
out.push('\n');
self.write_fields(out, bindings, indent + INDENT);
write_indent(out, indent);
out.push_str("in");
out.push('\n');
write_indent(out, indent + INDENT);
self.write_expr(out, body, indent + INDENT, 0);
}
fn write_function(&self, out: &mut String, params: &[Param], body: ExprId, indent: usize) {
out.push('(');
for (index, param) in params.iter().enumerate() {
if index > 0 {
out.push_str(", ");
}
self.write_param(out, param, indent);
}
out.push(')');
out.push_str(" =>");
if self.is_inline(body) {
out.push(' ');
self.write_expr(out, body, indent, 0);
} else {
out.push('\n');
write_indent(out, indent + INDENT);
self.write_expr(out, body, indent + INDENT, 0);
}
}
fn write_param(&self, out: &mut String, param: &Param, indent: usize) {
out.push_str(&param.name);
if let Some(constraint) = param.constraint {
out.push_str(": ");
self.write_expr(out, constraint, indent, 0);
}
}
fn write_match(&self, out: &mut String, scrutinee: ExprId, arms: &[MatchArm], indent: usize) {
out.push_str("match ");
self.write_expr(out, scrutinee, indent, 0);
out.push_str(" {");
if !arms.is_empty() {
out.push('\n');
for arm in arms {
write_indent(out, indent + INDENT);
self.write_expr(out, arm.pattern, indent + INDENT, 0);
out.push_str(": ");
self.write_expr(out, arm.body, indent + INDENT, 0);
out.push_str(";\n");
}
write_indent(out, indent);
}
out.push('}');
}
fn is_inline(&self, id: ExprId) -> bool {
match &self.ast.get(id).expr {
Expr::Literal(_)
| Expr::Ident(_)
| Expr::Import(_)
| Expr::RegexConstraint(_)
| Expr::Wildcard => true,
Expr::Path { base, .. } => self.is_inline(*base),
Expr::Call { callee, args } => {
self.is_inline(*callee) && args.iter().all(|arg| self.is_inline(*arg))
}
Expr::Unary { expr, .. } => self.is_inline(*expr),
Expr::Binary { lhs, rhs, .. } => self.is_inline(*lhs) && self.is_inline(*rhs),
Expr::Default { base, fallback } => self.is_inline(*base) && self.is_inline(*fallback),
Expr::CompareConstraint { value, .. } => self.is_inline(*value),
Expr::Array(items) => items.iter().all(|item| self.is_inline(*item)),
Expr::Object(fields) => fields.is_empty(),
Expr::Let { .. } | Expr::Function { .. } | Expr::Match { .. } => false,
}
}
}
fn expr_prec(expr: &Expr) -> u8 {
match expr {
Expr::Default { .. } => 1,
Expr::Binary { op, .. } => binary_prec(*op),
Expr::Unary { .. } | Expr::CompareConstraint { .. } => 17,
Expr::Path { .. } | Expr::Call { .. } => 19,
_ => 20,
}
}
fn binary_prec(op: BinaryOp) -> u8 {
match op {
BinaryOp::Patch => 3,
BinaryOp::And => 5,
BinaryOp::LogicalOr => 7,
BinaryOp::LogicalAnd => 9,
BinaryOp::Equal
| BinaryOp::NotEqual
| BinaryOp::Greater
| BinaryOp::GreaterEqual
| BinaryOp::Less
| BinaryOp::LessEqual => 11,
BinaryOp::Concat => 12,
BinaryOp::Add | BinaryOp::Sub => 13,
BinaryOp::Mul | BinaryOp::Div => 15,
}
}
fn binary_op_text(op: BinaryOp) -> &'static str {
match op {
BinaryOp::Add => "+",
BinaryOp::Sub => "-",
BinaryOp::Mul => "*",
BinaryOp::Div => "/",
BinaryOp::Concat => "++",
BinaryOp::Equal => "==",
BinaryOp::NotEqual => "!=",
BinaryOp::Greater => ">",
BinaryOp::GreaterEqual => ">=",
BinaryOp::Less => "<",
BinaryOp::LessEqual => "<=",
BinaryOp::LogicalAnd => "&&",
BinaryOp::LogicalOr => "||",
BinaryOp::And => "&",
BinaryOp::Patch => "//",
}
}
fn compare_op_text(op: CompareOp) -> &'static str {
match op {
CompareOp::Gt => ">",
CompareOp::Gte => ">=",
CompareOp::Lt => "<",
CompareOp::Lte => "<=",
CompareOp::Eq => "==",
}
}
fn write_indent(out: &mut String, indent: usize) {
for _ in 0..indent {
out.push(' ');
}
}
fn write_quoted(out: &mut String, value: &str) {
out.push('"');
for ch in value.chars() {
match ch {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
ch if ch.is_control() => {
let _ = write!(out, "\\u{:04x}", ch as u32);
}
ch => out.push(ch),
}
}
out.push('"');
}
fn reject_comments(source_id: SourceId, source: &str) -> Result<()> {
if let Some(offset) = comment_offset(source) {
return Err(Diagnostic::syntax(
Span::new(source_id, offset, offset + 1),
"formatter does not yet preserve comments",
));
}
Ok(())
}
fn comment_offset(source: &str) -> Option<usize> {
let bytes = source.as_bytes();
let mut index = 0;
while index < bytes.len() {
match bytes[index] {
b'"' => {
index += 1;
while index < bytes.len() {
match bytes[index] {
b'\\' => index += 2,
b'"' => {
index += 1;
break;
}
_ => index += 1,
}
}
}
b'#' => return Some(index),
_ => index += 1,
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse_source;
#[test]
fn formats_top_level_fields() {
let formatted = format_source("port=Int&>=1 default 8080;name=String;").unwrap();
assert_eq!(
formatted,
"port = Int & >= 1 default 8080;\nname = String;\n"
);
parse_source(&formatted).unwrap();
}
#[test]
fn formats_nested_objects() {
let formatted =
format_source("Server={host=String default \"localhost\";port=Int&>0;};").unwrap();
assert_eq!(
formatted,
"Server = {\n host = String default \"localhost\";\n port = Int & > 0;\n};\n"
);
parse_source(&formatted).unwrap();
}
#[test]
fn formats_let_function_match_and_array() {
let source = "let f=(x:Int)=>match x{_: [1,{a=2;}];};in f(1)";
let formatted = format_source(source).unwrap();
assert_eq!(
formatted,
"let\n f = (x: Int) =>\n match x {\n _: [\n 1,\n {\n a = 2;\n },\n ];\n };\nin\n f(1)\n"
);
parse_source(&formatted).unwrap();
}
#[test]
fn preserves_needed_parentheses() {
let formatted = format_source("value=(1+2)*3;").unwrap();
assert_eq!(formatted, "value = (1 + 2) * 3;\n");
parse_source(&formatted).unwrap();
}
#[test]
fn rejects_comments_instead_of_dropping_them() {
let error = format_source("# keep me\nvalue = 1;").unwrap_err();
assert_eq!(error.message, "formatter does not yet preserve comments");
}
}
-2
View File
@@ -7,7 +7,6 @@ pub mod constraints;
pub mod diagnostic;
pub mod embedding;
pub mod eval;
pub mod formatter;
mod lexer;
pub mod module;
pub mod parser;
@@ -22,7 +21,6 @@ pub use decodal_derive::Decodal;
pub use diagnostic::{Diagnostic, DiagnosticKind, Result};
pub use embedding::{HostField, HostValue};
pub use eval::{Engine, format_diagnostic_with};
pub use formatter::{format_source, format_source_with_source_id};
pub use module::{EmptyLoader, LoadedSource, Module, SourceLoader};
pub use parser::{ParseOutput, Parser, SourceForm, parse_source, parse_source_with_source_id};
pub use runtime::{Constraint, Data, ExprRef, LiteralValue, ModuleId, PrimitiveType, RuntimeValue};
+1 -19
View File
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use decodal::{
Data, Diagnostic, DiagnosticKind, EmptyLoader, Engine, LoadedSource, SourceId, SourceLoader,
Span, format_diagnostic_with, format_source,
Span, format_diagnostic_with,
};
use wasm_bindgen::prelude::*;
@@ -11,17 +11,6 @@ pub fn evaluate(source: &str) -> String {
encode_result(evaluate_inner(source))
}
#[wasm_bindgen(js_name = formatSource)]
pub fn format_source_json(source: &str) -> String {
match format_source(source) {
Ok(formatted) => format!("{{\"ok\":true,\"source\":{}}}", json_string(&formatted)),
Err(error) => format!(
"{{\"ok\":false,\"error\":{}}}",
json_string(&format_diagnostic_with_root(&error, "playground"))
),
}
}
#[wasm_bindgen(js_name = evaluateProject)]
pub fn evaluate_project(entry: &str, files_json: &str) -> String {
encode_result(evaluate_project_inner(entry, files_json))
@@ -225,13 +214,6 @@ fn json_string(value: &str) -> String {
mod tests {
use super::{evaluate_project_inner, normalize_path, resolve_import};
#[test]
fn formats_source_for_web() {
let output = super::format_source_json("value={a=1;};");
assert!(output.contains("\"ok\":true"));
assert!(output.contains("value = {\\n a = 1;\\n};\\n"));
}
#[test]
fn normalizes_virtual_paths() {
assert_eq!(
+1 -1
View File
@@ -8,7 +8,7 @@ The public surface is intentionally organized by use case: execute Decodal with
### Rust crate
The `decodal` crate is the primary Rust runtime and embedding API.
It owns parsing, formatting, evaluation, materialization, diagnostics, host-provided values, and schema/decode traits.
It owns parsing, evaluation, materialization, diagnostics, host-provided values, and schema/decode traits.
Rust applications should use this crate when they want to load Decodal source, evaluate it, or embed Decodal into a host program.
Important paths:
-50
View File
@@ -1,50 +0,0 @@
# Formatting
Decodal includes an initial source formatter for parsed Decodal code.
The formatter is available from the Rust crate, the CLI, the WebAssembly package, and the playground.
## CLI
Print formatted source to stdout:
```sh
decodal fmt config.dcdl
```
Format in place:
```sh
decodal fmt --write config.dcdl
```
Read from stdin:
```sh
cat config.dcdl | decodal fmt -
```
## Rust
```rust
let formatted = decodal::format_source("Server={port=Int default 8080;};")?;
```
## WebAssembly
```js
import init, { formatSource } from 'decodal-wasm';
await init();
const result = JSON.parse(formatSource('Server={port=Int default 8080;};'));
if (result.ok) {
console.log(result.source);
} else {
console.error(result.error);
}
```
## Current limitation
The formatter currently rejects source containing line comments rather than silently dropping them.
Comment-preserving formatting requires attaching comments to syntax nodes or formatting from a concrete syntax tree, and should be implemented before comment-heavy source is formatted automatically.
+4 -5
View File
@@ -7,8 +7,7 @@ Decodal は Deferred Constraint Data Language、略称 DCDL のプロジェク
1. [Introduction](./introduction.md)
2. [Components](./components.md)
3. [Formatting](./formatting.md)
4. [Language Specification](./language/index.md)
3. [Language Specification](./language/index.md)
1. [Lexical Structure and Syntax](./language/syntax.md)
2. [Value](./language/value/index.md)
1. [String](./language/value/string.md)
@@ -37,7 +36,7 @@ Decodal は Deferred Constraint Data Language、略称 DCDL のプロジェク
9. [Materialization and Errors](./language/materialization-and-errors.md)
10. [Naming Conventions](./language/naming.md)
11. [Examples](./language/examples.md)
5. [Implementation Design](./design/index.md)
4. [Implementation Design](./design/index.md)
1. [Execution Pipeline](./design/execution-pipeline.md)
2. [Runtime Model](./design/runtime-model.md)
3. [Thunk and Lazy Evaluation](./design/thunk-and-lazy-evaluation.md)
@@ -45,5 +44,5 @@ Decodal は Deferred Constraint Data Language、略称 DCDL のプロジェク
5. [Diagnostics and Fallback](./design/diagnostics-and-fallback.md)
6. [Embedding API](./design/embedding-api.md)
7. [Features](./design/features.md)
6. [Development](./development.md)
7. [Open Issues](./open-issues.md)
5. [Development](./development.md)
6. [Open Issues](./open-issues.md)
+6 -6
View File
@@ -22,15 +22,15 @@ deno add jsr:@hare/decodal-wasm
## Usage
```js
import init, { evaluateProject, formatSource } from 'decodal-wasm';
import init, { evaluateProject } from 'decodal-wasm';
await init();
const formatted = JSON.parse(formatSource('Server={port=Int default 8080;};'));
console.log(formatted.source);
const result = evaluateProject('main.dcdl', JSON.stringify({
'main.dcdl': 'Server = { port = Int default 8080; };',
const result = evaluateProject(JSON.stringify({
entry: 'main.dcdl',
files: {
'main.dcdl': 'Server = { port = Int default 8080; };',
},
}));
console.log(JSON.parse(result));
-3
View File
@@ -5,15 +5,12 @@ export function evaluate(source: string): string;
export function evaluateProject(entry: string, files_json: string): string;
export function formatSource(source: string): string;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly evaluate: (a: number, b: number) => [number, number];
readonly evaluateProject: (a: number, b: number, c: number, d: number) => [number, number];
readonly formatSource: (a: number, b: number) => [number, number];
readonly __wbindgen_externrefs: WebAssembly.Table;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
-19
View File
@@ -40,25 +40,6 @@ export function evaluateProject(entry, files_json) {
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
}
}
/**
* @param {string} source
* @returns {string}
*/
export function formatSource(source) {
let deferred2_0;
let deferred2_1;
try {
const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.formatSource(ptr0, len0);
deferred2_0 = ret[0];
deferred2_1 = ret[1];
return getStringFromWasm0(ret[0], ret[1]);
} finally {
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
}
}
function __wbg_get_imports() {
const import0 = {
__proto__: null,
Binary file not shown.
-1
View File
@@ -3,7 +3,6 @@
export const memory: WebAssembly.Memory;
export const evaluate: (a: number, b: number) => [number, number];
export const evaluateProject: (a: number, b: number, c: number, d: number) => [number, number];
export const formatSource: (a: number, b: number) => [number, number];
export const __wbindgen_externrefs: WebAssembly.Table;
export const __wbindgen_malloc: (a: number, b: number) => number;
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
@@ -34,15 +34,15 @@ deno add jsr:@hare/decodal-wasm
## Usage
\`\`\`js
import init, { evaluateProject, formatSource } from 'decodal-wasm';
import init, { evaluateProject } from 'decodal-wasm';
await init();
const formatted = JSON.parse(formatSource('Server={port=Int default 8080;};'));
console.log(formatted.source);
const result = evaluateProject('main.dcdl', JSON.stringify({
'main.dcdl': 'Server = { port = Int default 8080; };',
const result = evaluateProject(JSON.stringify({
entry: 'main.dcdl',
files: {
'main.dcdl': 'Server = { port = Int default 8080; };',
},
}));
console.log(JSON.parse(result));
-1
View File
@@ -20,7 +20,6 @@ export const docs = Object.fromEntries(
export const nav = [
{ title: 'Introduction', slug: 'introduction' },
{ title: 'Components', slug: 'components' },
{ title: 'Formatting', slug: 'formatting' },
{
title: 'Language Specification',
slug: 'language',
@@ -15,7 +15,6 @@ import ManualLayout from '../layouts/ManualLayout.astro';
</label>
<button id="load-example" type="button">Load</button>
<p id="status" class="status">Loading WASM...</p>
<button id="format" disabled>Format</button>
<button id="run" disabled>Run</button>
</div>
</div>
+1 -18
View File
@@ -1,4 +1,4 @@
import init, { evaluateProject, formatSource } from 'decodal-wasm';
import init, { evaluateProject } from 'decodal-wasm';
import { EditorView, basicSetup } from 'codemirror';
import { keymap } from '@codemirror/view';
import { decodal } from 'decodal-codemirror';
@@ -10,7 +10,6 @@ const starterProject = playgroundExamples[0];
const editorHost = document.getElementById('editor');
const output = document.getElementById('output');
const run = document.getElementById('run');
const formatButton = document.getElementById('format');
const status = document.getElementById('status');
const fileTree = document.getElementById('file-tree');
const activeFile = document.getElementById('active-file');
@@ -177,20 +176,6 @@ function execute() {
output.classList.toggle('error', !result.ok);
}
function formatActiveFile() {
const result = JSON.parse(formatSource(getEditorText()));
if (!result.ok) {
output.textContent = result.error;
output.classList.add('error');
return;
}
setEditorText(result.source);
project.files[project.activePath] = result.source;
saveProject();
output.textContent = 'Formatted.';
output.classList.remove('error');
}
function renderFileTree() {
const tree = buildTree(Object.keys(project.files).sort());
fileTree.replaceChildren(renderTreeList(tree.children));
@@ -244,7 +229,6 @@ function compareNodes(a, b) {
try {
await init();
run.disabled = false;
formatButton.disabled = false;
status.textContent = '';
execute();
} catch (error) {
@@ -252,7 +236,6 @@ try {
}
run.addEventListener('click', execute);
formatButton.addEventListener('click', formatActiveFile);
loadExample.addEventListener('click', () => {
const example = playgroundExamples.find((item) => item.id === exampleSelect.value);
if (!example) return;