smile-js

Javascript Smile implementation.

Overview

This project is an implementation of Jackson's Smile format. The library supports encoding and decoding.

Documentation

Typedoc

Command-line tools

smile-cli

smile-cli                            # installed globally
node_modules/smile-js/bin/smile-cli  # [npm] installed locally
pnpm exec smile-cli                  # [pnpm] installed locally
Usage: smile-cli [options] [command]

SMILE CLI

Options:
  -V, --version                            output the version number
  -h, --help                               display help for command

Commands:
  encode [options] [jsonFile] [smileFile]  Encode JSON to SMILE
  decode [options] [smileFile] [jsonFile]  Decode SMILE to JSON
  help [command]                           display help for command

HTML Script Tag

To use smile-js via the HTML script tag:

<script src="https://cdn.jsdelivr.net/npm/smile-js@0.10.1/dist/smile-js.iife.js"></script>

The module will be exported as windows.smile.

Example

Demo

<!DOCTYPE html>
<html lang="en-US">
<head>
    <title>smile-js test</title>

    <script src="https://cdn.jsdelivr.net/npm/smile-js@0.10.1/dist/smile-js.iife.js"></script>
    <script>
        function onChooseFile(e) {
            const file = e.target.files.item(0)
            file.arrayBuffer()
                .then(arrayBuffer => {
                    const data = new Uint8Array(arrayBuffer);
                    try {
                        const o = window.smile.decode(data);
                        console.log(o);
                        document.getElementById("output").innerText = JSON.stringify(o, null, 2);
                    } catch (e) {
                        alert(e);
                    }
                })
                .catch(e => {
                    alert(e);
                });
        }
    </script>
</head>
<body>
<div>
    <label for="file">Select SMILE-encoded file</label>
    <input id="file" type="file" onchange="onChooseFile(event)"/>
</div>
<div>
    <label for="output">JSON representation:</label>
    <pre id="output"></pre>
</div>
</body>
</html>

Svelte example

Source

Demo

App.svelte

<script lang="ts">
    import {decode, encode} from 'smile-js';
    import {isInteger, parse, stringify} from 'lossless-json';
    import {Base64} from 'js-base64';

    let decodedJson: string = '';
    let inputJson: string = '';

    function onChooseEncodedFile(e: Event) {
        const target = e.target as HTMLInputElement;
        if (!target.files || (target.files.length < 1)) {
            return;
        }
        const file = target.files.item(0)
        if (!file) {
            return;
        }
        file.arrayBuffer()
            .then(arrayBuffer => {
                const data = new Uint8Array(arrayBuffer);
                try {
                    const o = decode(data);
                    console.log(o);
                    const json = stringify(o, null, '  ');
                    if (json !== undefined) {
                        decodedJson = json;
                    } else {
                        alert('could not JSON stringify object')
                    }
                } catch (e) {
                    alert(e);
                }
            })
            .catch(e => {
                alert(e);
            });
    }

    function onClickEncode(e: Event) {
        try {
            const o = parse(inputJson, null, parseNumber);
            console.log('input', o);
            const encodedData = encode(o);
            download('encoded.smile', 'application/x-jackson-smile', encodedData);
        } catch (e) {
            alert(e);
        }
    }

    function download(filename: string, contentType: string, data: Uint8Array) {
        const element = document.createElement('a');
        element.setAttribute('href', `data:${contentType};base64,${Base64.fromUint8Array(data)}`);
        element.setAttribute('download', filename);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    }

    function parseNumber(v: string): unknown {
        if (isInteger(v)) {
            const b = BigInt(v);
            if ((b >= BigInt(Number.MIN_SAFE_INTEGER)) && (b <= BigInt(Number.MAX_SAFE_INTEGER))) {
                return Number(b);
            } else {
                return b;
            }
        } else {
            return parseFloat(v);
        }
    }
</script>

<h1>smile-js demo</h1>

<h2>Decode</h2>

<div>
    <label for="file">Select SMILE-encoded file</label>
    <input id="file" type="file" on:change={onChooseEncodedFile}/>
</div>
<div>
    <label for="output">JSON representation:</label>
    <pre id="output">{decodedJson}</pre>
</div>

<hr>

<h2>Encode</h2>

<button on:click={onClickEncode}>Encode</button>
<textarea class="inputJson" bind:value={inputJson}></textarea>

<style>
    .inputJson {
        width: 100%;
        height: 20em;
    }
</style>