pre/phpx

Installs: 250

Dependents: 1

Suggesters: 0

Security: 0

Stars: 70

Watchers: 4

Forks: 3

Open Issues: 1

Type:pre-compiler

0.5.0 2021-07-16 04:13 UTC

This package is auto-updated.

Last update: 2024-10-16 10:54:58 UTC


README

Documentation can be found at preprocess.io.

Motivation

I wanted to write a custom compiler, and this syntax appeals to me. It's not a replacement for Javascript, or even a very good implementation. But, I like it. That's all that counts.

If you want to write component-based code, without writing Javascript; then this might work for you.

Getting started

  • Clone the repository
  • Install the Compoer dependencies
  • Run the tests or execute the example scripts

This should work on PHP 7.2 (where it was developed and tested). Make an issue if it's not working on 7.2 or if you'd like to see things added.

What does it render?

The goal was to decouple the compiler from the renderers. Once the Pre\Phpx\Html renderer moves out, you'll need to import it into your project or create a custom render function. The Pre\Phpx\Html render function looks like this:

public function render($name, $props = null)
{
    $props = $this->propsFrom($props);

    if ($function = globalFunctionMatching($name)) {
        return call_user_func($function, $props);
    }

    if ($class = globalClassMatching($name)) {
        return (new $class($props))->render();
    }

    // render HTML from a list of allowed elements...

    return $this->format("...");
}

This means you can define your own namespaced functions and classes, and use them in the Pre\Phpx\Html render function, like:

namespace Example\Application;

// don't forget to define or import render
// everywhere you use HTML-in-PHP syntax
use function Pre\Phpx\Html\render;

function MyForm($props) {
    return (
        <form>
            {$props->showLabel ? <label htmlFor={"email"}>Email</label> : null}
            <input type={"text"} name={"email"} id={"email"} />
        </form>
    );
}

// ...later

print render(<Example.Application.MyForm />);

If you'd prefer to have your components automatically prefixed, define your own render function, You can extend the Pre\Phpx\Html render function:

namespace Example\Application;

use function Pre\Phpx\classMatching;
use function Pre\Phpx\functionMatching;
use function Pre\Phpx\Html\render as renderHtml;
use function Pre\Phpx\Html\propsFrom;

define("NAMESPACES", [
    // remove this if you only have
    // namespaced classes and functions
    "global",

    // classes and functions will
    // be loaded from this namespace
    "Example\\Application",
]);

function render($name, $props = null)
{
    $props = propsFrom($props);

    if ($function = functionMatching(NAMESPACES, $name)) {
        return call_user_func($function, $props);
    }

    if ($class = classMatching(NAMESPACES, $name)) {
        return (new $class($props))->render();
    }

    return renderHtml($name, $props);
}

// ...later

print render(<MyForm />);

You can define components as functions or classes:

function MyForm($props) {
    // render things...
}

// ...or

class MyForm
{
    public function __construct($props)
    {
        // ...store and manipulate the props
    }

    public function render()
    {
        // render things...
    }
}

Since you can define a custom render function, you can decide what your components are allowed to return. HTML-in-PHP syntax is converted to the following form:

use function Pre\Phpx\Html\Example\render;

function MyForm($props) {
    return (
        <form>
            {$props->showLabel ? <label htmlFor={"email"}>Email</label> : null}
            <input type={"text"} name={"email"} id={"email"} />
        </form>
    );
}

// ...becomes

use function Pre\Phpx\Html\Example\render;

function MyForm($props)
{
    return render("form", [
        "children" => [
            $props->showLabel ?
                render("label", [
                    "htmlFor" => "email",
                    "children" => "Email",
                ]) :
                null,
            render("input", [
                "type" => "text",
                "name" => "email",
                "id" => "email",
            ]),
        ],
    ]);
}

You decide what your components return and what your render function does. The Pre\Phpx\Html render function outputs strings of HTML, and expects components rendered by it to return strings (so that they can be concatenated in an array of children).

Returning null will also work.

Roadmap

  • Support HTML tag warnings and rewriting
  • Move HTML renderer to its own library
  • Set up StyleCI and Travis
  • Write more tests
  • Experiment with other renderers
  • Document like it's 1999