npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@yagni-js/yagni-parser

v0.4.1

Published

Yet another functional HTML to Javascript compiler (compatible with @yagni-js/yagni-dom)

Downloads

5

Readme

yagni-parser

HTML to Javascript compiler. Generated code is compatible with yagni-dom hyperscript dialect.

Library code is linted using eslint-plugin-fp and eslint-plugin-better. The code is almost purely functional with the following exceptions:

  • it throws an error if source html has multiple root elements
  • it throws an error if opening/closing tags differ somewhere in html
  • it throws an error if unclosed tags exist in html
  • it uses new keyword to create new tokenizer to parse html
  • it uses node path module to extract partial filename

The library uses Tokenizer from an excellent parse5 library to tokenize source html and convert it to yagni-dom compatible ES6 module.

This library is not expected to be used on it's own, please use rollup plugin or webpack loader to convert html to ES6 module.

Features

  • transforms source html to javascript function (so called view function), which can be called later to produce a factory function which when called will generate proper DOM tree
  • generates unary view function - it accepts only one argument named ctx which is expected to be an object holding context to render view (perfectly suited for yagni-dom library)
  • supports concept of partials using partial tag (see below)
  • supports {{ ctx.foo }} syntax in attribute/property value definition and in static text to allow access to passed into view function context (this syntax will be transpiled to ES6 template literal syntax - be aware of supported browsers)
  • allows only single root tag in html template
  • checks for dom tree structure simple errors
  • strips whitespace from html
  • allows to set tag properties values (use prop-foo attribute to set foo property value on tag)
  • allows to set tag attribute or property value by reference using @ as a prefix of attribute/property name: @prop-onclick="ctx.onlick" (useful to set tag event handlers)
  • allows to use newline in attribute value definition (useful for readability sometimes)
  • normalizes whitespace in tag attributes/properties values and in static text (replaces newlines to single whitespace, replaces multiple consecutive whitespace characters to single whitespace character)

Partials

Partial is an html template which can be reused by html templates or other partials.

To include partial in template you should use partial tag and specify path to source using src attribute:


<partial src="./foo.html"></partial>

Generated javascript module will be the following:


import { view as fooView } from "./foo.html";

export function view(ctx) {
  return fooView(ctx);
}

Tag partial doesn't support any nested declarations (such as text or other tags inside), they will be silently dropped.

Partial can be conditionally included using p-if or p-if-not tag attributes:


<div class="user-menu">
    <partial src="./login-form.html" p-if-not="ctx.user.isLoggedIn"></partial>
    <partial src="./logout-form.html" p-if="ctx.user.isLoggedIn"></partial>
</div>

Partial can me mapped over an array of items using p-map tag attribute:


<nav class="mainmenu">
    <partial src="./menu/item.html" p-map="ctx.mainmenu"></partial>
</nav>

Partial can use p-map and p-if/p-if-not attributes simultaneously, which means partial will be mapped over an array of items only if p-if/p-if-not condition evaluates to true:


<nav class="relatedmenu">
    <partial src="./menu/item.html" p-if="ctx.showRelatedMenu" p-map="ctx.relatedmenu" related="yes"></partial>
</nav>

Installation

Using npm:


$ npm install --save-dev @yagni-js/yagni-parser @yagni-js/yagni-dom @yagni-js/yagni

Using yarn:


$ yarn add -D @yagni-js/yagni-parser @yagni-js/yagni-dom @yagni-js/yagni

Usage

Source code is written using ES6 modules, built using rollup and distributed in two formats - as CommonJS module and as ES6 module.

CommonJS usage:


const yp = require('@yagni-js/yagni-parser');

ES6 module usage:


import * as yp from '@yagni-js/yagni-parser';
// or
import { parse } from '@yagni-js/yagni-parser';

Documentation

Not yet available, please check sources.

Example

Suppose we have the following HTML template:


<div class="root">
    <div class="header">
        <h1>Header</h1>
        <partial src="./login-form.html" p-if-not="ctx.user.isLoggedIn"></partial>
        <partial src="./logout-form.html" p-if="ctx.user.isLoggedIn"></partial>
    </div>
    <div class="main">
        <div class="sidebar">
            <nav class="mainmenu">
                <partial src="./menu/item.html" p-map="ctx.mainmenu"></partial>
            </nav>
        </div>
        <div class="content" id="content">
            <div class="content-body" id="content-body">Content</div>
            <nav class="relatedmenu">
                <partial src="./menu/item.html" p-if="ctx.showRelatedMenu" p-map="ctx.relatedmenu" related="yes"></partial>
            </nav>
        </div>
    </div>
    <div class="footer">Footer</div>
</div>

After compilation it will be translated into the following code:


import { isArray, merge, pipe } from "@yagni-js/yagni";
import { h, hText, hSkip } from "@yagni-js/yagni-dom";
import { view as loginFormView } from "./login-form.html";
import { view as logoutFormView } from "./logout-form.html";
import { view as itemView } from "./menu/item.html";


export function view(ctx) {
  return h("div", {"class": "root"}, {}, [
    h("div", {"class": "header"}, {}, [
      h("h1", {}, {}, [
        hText("Header")
      ]),
      !(ctx.user.isLoggedIn) ? (loginFormView(ctx)) : hSkip(),
      (ctx.user.isLoggedIn) ? (logoutFormView(ctx)) : hSkip()
    ]),
    h("div", {"class": "main"}, {}, [
      h("div", {"class": "sidebar"}, {}, [
        h("nav", {"class": "mainmenu"}, {}, [
          isArray(ctx.mainmenu) ? ctx.mainmenu.map(itemView) : hSkip()
        ])
      ]),
      h("div", {"class": "content", "id": "content"}, {}, [
        h("div", {"class": "content-body", "id": "content-body"}, {}, [
          hText("Content")
        ]),
        h("nav", {"class": "relatedmenu"}, {}, [
          (ctx.showRelatedMenu) ? (isArray(ctx.relatedmenu) ? ctx.relatedmenu.map(pipe([merge({"related": "yes"}), itemView])) : hSkip()) : hSkip()
        ])
      ])
    ]),
    h("div", {"class": "footer"}, {}, [
      hText("Footer")
    ])
  ]);
}

License

Unlicense