Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sbsoftware/js.cr

Experimental tool to generate JavaScript code from Crystal
https://github.com/sbsoftware/js.cr

Last synced: 3 months ago
JSON representation

Experimental tool to generate JavaScript code from Crystal

Awesome Lists containing this project

README

        

# `js.cr`

An experimental tool to generate JavaScript code from Crystal code.

## Contents

* [Goals](#goals)
* [Examples](#examples)
* [Code Snippets](#javascript-code)
* [`_call`](#_call)
* [Functions](#javascript-functions)
* [Classes](#javascript-classes)
* [Files](#javascript-files)
* [Aliases](#aliases)
* [Modules](#javascript-modules)
* [Loops](#loops)

## Goals

The most important idea behind this project is to create the ability to reference JavaScript functions, classes and modules in Cystal code using typechecked entities instead of strings.

Initially I wanted to leverage Crystal's type system to have my JavaScript code typechecked at compile time, but that turned out to be too much to start with. It remains a goal to reintroduce that feature at some point, but for now you can generate _invalid_ JavaScript with this library.

Please note that this is still very experimental and probably lacks essential features to be genuinely used. So far I am employing it to generate stimulus controllers which toggle some classes of HTML elements.

Also, I skipped any whitespacing for now as I wanted to have my proof of concept as fast as possible. Not sure if I will ever deem it necessary to add it. The specs are still quite readable because I include whitespace in the examples and only remove it before comparing to the results.

## Examples

### JavaScript Code

Just want to output some loose snippet of JavaScript code? Use the `JS::Code` base class. You can print your code directly into a `` tag of your favorite template engine via `.to_js` if you want.

```crystal
require "js"

class MyCode < JS::Code
def_to_js do
console.log("Hello World!")
end
end

puts MyCode.to_js
```

#### `_call`

In Crystal, there are no object properties but just method calls. Without any type information about the JS code you are calling, `js.cr` cannot know whether you want to reference a property or call a function without any arguments on an object.
It therefore always assumes a property reference. If you need a function call instead, just append `._call` to it.
Note that this isn't necessary if your call has arguments.

```crystal
require "js"

class MyCallCode < JS::Code
def_to_js do
a = SomeUnknownJSConstant.somePropertyOfIt
b = SomeUnknownJSConstant.someFunctionOfIt._call
c = SomeUnknownJSConstant.someOtherFunctionOfIt("foo")
end
end

# => var a = SomeUnknownJSConstant.somePropertyOfIt;
# => var b = SomeUnknownJSConstant.someFunctionOfIt();
# => var c = SomeUnknownJSConstant.someOtherFunctionOfIt("foo");
puts MyCallCode.to_js
```

### JavaScript Functions

If you were wondering how to define a function within `JS::Code.def_to_js` - that's not possible. Well, technically it is via a `_literal_js` call but that's dirty and there is a better way:

```crystal
require "js"

class MyFunction < JS::Function
def_to_js do |foo|
console.log(foo)
end
end

puts MyFunction.to_js
```

You _could_ have that printed into a `<script>` tag again via `.to_js` and reference it in an `onclick` attribute by calling `.to_js_call`. Not sure how hip that is anymore.

```ecr
<html>
<head>
<title>JavaScript!</title>
<script><%= MyFunction.to_js %>


">Print "test" to the console!