DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

Open Source Adventures: Episode 23: Imba 2 JSON Beautifier

Let's port another Imba 1 app to Imba 2 - JSON Beautifier, which you can see in action here.

The app is very simple, has just one component, and outsources all logic to json-stringify-pretty-compact package.

The most interesting part about it is that it uses Cypress for integration testing, so in the next post I'll also try to setup Cypress integration tests for the Imba 2 version too.

Imba 1 app.imba

let stringify = require("json-stringify-pretty-compact")

tag App
  def setup
    @maxlen = 80
    @indent = 2
    @text = JSON.stringify({hello: "world"})
    @error = null

  def prettify
    try
      let indent = parseInt(@indent)
      let json = JSON.parse(@text)
      let spaces = Array.from({length: indent+1}).join(" ")
      @text = stringify(json, {maxLength: @maxlen, indent: spaces})
    catch e
      @error = e

  def clear_error
    @error = null

  def upload(event)
    let file = event.native:target:files[0]
    return unless file
    let reader = FileReader.new

    reader:onload = do |event|
      @text = event:target:result
      @error = nil
      Imba.commit
    reader.read-as-text(file)

  def render
    <self>
      <header>
        "JSON Beautifier"
      <textarea[@text] rows=10 :input.clear_error>
      if @error
        <div.error>
          @error
      <div.controls>
        <input#file type="file" :change.upload>
        <label for="indent">
          "Indent"
        <input#indent[@indent] type="number" min=0>
        <label for="maxlen">
          "Max row length"
        <input#maxlen[@maxlen] type="number" min=0>
        <button :click.prettify>
          "Prettify"

Imba.mount <App>
Enter fullscreen mode Exit fullscreen mode

Imba 1 app.scss

@import 'normalize-scss';
@include normalize();

.App {
  display: flex;
  flex-direction: column;
  align-items: center;

  header {
    font-size: 64px;
    text-align: center;
  }

  textarea {
    min-width: 50vw;
    margin-bottom: 10px;
  }

  .controls {
    display: grid;
    grid-row-gap: 5px;
    margin: auto;

    label { grid-column: 1; }
    input { grid-column: 2; }
    button { grid-column: 2; }
  }

  .error {
    background-color: #fcc;
    min-width: 50vw;
    padding: 5px;
    border: 1px solid #800;
  }
}
Enter fullscreen mode Exit fullscreen mode

Imba 2 app.imba

import stringify from "json-stringify-pretty-compact"

tag app
  prop maxlen = 80
  prop indent = 2
  prop text = JSON.stringify({hello: "world"})
  prop error

  def prettify
    try
      let json = JSON.parse(text)
      let spaces = Array.from({length: parseInt(indent)+1}).join(" ")
      text = stringify(json, {maxLength: parseInt(maxlen), indent: spaces})
    catch e
      error = ""+e
    imba.commit()

  def clear_error
    error = null

  def upload(event)
    let file = event.target.files[0]
    return unless file
    let reader = new FileReader

    reader.onload = do |event|
      text = event.target.result
      error = nil
      imba.commit()
    reader.readAsText(file)

  <self>
    <header>
      "JSON Beautifier"
    <textarea bind=text rows=10 :input.clear_error>
    if error
      <div.error>
        error
    <div.controls>
      <input#file type="file" :change.upload>
      <label for="indent">
        "Indent"
      <input#indent bind=indent type="number" min=0>
      <label for="maxlen">
        "Max row length"
      <input#maxlen bind=maxlen type="number" min=0>
      <button :click.prettify>
        "Prettify"

  css
    display: flex
    flex-direction: column
    align-items: center
    ff: sans

    header
      font-size: 64px
      text-align: center

    textarea
      min-width: 50vw
      margin-bottom: 10px

    .controls
      display: grid
      grid-row-gap: 5px
      margin: auto

      label
        grid-column: 1
      input, button
        grid-column: 2

    .error
      background-color: #fcc
      min-width: 50vw
      padding: 5px
      border: 1px solid #800

imba.mount <app>
Enter fullscreen mode Exit fullscreen mode

This is a very straightforward translation.

We need to convert Error to String, as Imba 2 doesn't like putting Error objects directly in the output, but that's probably a good idea anyway.

Other than that, it's just minor syntactic changes.

By the way I wonder if any framework will ever offer good solution for the label for problem. Right now they inherently use globally scoped ids.

Source code

Source code is in imba2-json-beautifier repository.

You can also see the live version here.

Coming next

In the next episode we'll try to add Cypress tests to this app.

Top comments (0)