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

@peter.naydenov/morph

v0.0.3

Published

Template engine

Downloads

201

Readme

Morph (@peter.naydenov/morph)

Experimental stage. Not tested well yet.

version license GitHub issues GitHub top language npm package minimized gzipped size (select exports)

General Information

Morph has a logic-less template syntax. Placeholders are places surrounded by double curly braces {{ }} and they represents the pleces where the data will be inserted.

Engine is text based, so it can be used for HTML, CSS, config files, source code, etc. Some features of Morph:

  • Simple logic-less template syntax;
  • Builtin storage;
  • Powerfull action system for data decoration;
  • Nesting templates as part of the action system;
  • Partial rendering (render only available data);
  • Option to connect templates to external data sources;
  • Post process plugin mechanism;

Installation

npm install @peter.naydenov/morph

Morph can be used in browser and node.js.

import morph from "@peter.naydenov/morph"
// Morph supports also require:
// const morph = require("@peter.naydenov/morph")

Basic Usage

import morph from "@peter.naydenov/morph"

const myTemplateDescription = {
                 template: `Hello, {{name}}!` // simple template - a string with a placeholder
            }
const myTemplate = morph.build ( myTemplateDescription ); // myTemplate is a render function
const htmlBlock = myTemplate ( { name: 'Peter' } )        // Provide data to the render function and get the result
// htmlBlock === 'Hello, Peter!'

Morph contains also a builtin template storage. Instead of creating variable for each template, we can use the storage.

// add template to the storage. Automatically builds the render function
morph.add ( 'myTemplate', myTemplateDescription ) 
// get template from the storage and render it
const htmlBlock = morph.get ( 'myTemplate' )({ name: 'Peter' }) 

Let's see a more complex example before we go into details:

const myTemplateDescription = {
              template: `Hello, {{ person : a, >getReady }}! Your age is {{ person : >getAge}}.` 
            , helpers: {
                            getReady: (person) => {
                                            return {
                                                      text: person.name
                                                    , href: person.web
                                                }
                                        }
                          , a: `<a href="{{href}}">{{text}}</a>`
                          , getAge: (person) => person.age
                    }
            }
const myTemplate = morph.build ( myTemplateDescription );
const htmlBlock = myTemplate ( { person: {
                                              name: 'Peter'
                                            , age : 40
                                            , web : 'example.com'
                                        } 
                                })
// htmlBlock === Hello, <a href="example.com">Peter</a>! Your age is 40.

Methods

  build   : 'Build a component from template description'
, get     : 'Get a component from component storage'
, add     : 'Add a component to component storage'
, list    : 'List the names of all components in the component storage'
, clear   : 'Clear up all the components in the storage'
, remove  : 'Remove a template from component storage'

Template Description Structure

Templates are objects with tree properties: template, helpers, and handshake:

const myTemplateDescription = {
      template: `` // (required) Template string
    , helpers: {
                // (optional) Functions and templates used by actions to decorate the data
        }
    , handshake: {
                // (optional) Example data used to render the template.
        }
}

Template is a string with placeholders where we render our external data. It's a skeleton of the template. Placeholders are the dynamic parts of the template.

Helpers are a extra templates or functions needed for rendering the template. Example:

const myTemplateDescription = {
      template: `
                <h1>{{title}}</h1>
                <ul>
                    {{list:li,a}}
                </ul>
            `
    , helpers: {
                a: `<a href="{{href}}">{{text}}</a>`,
                li: `<li>{{text}}</li>`
            }
    , handshake: {
                title: 'My title'
              , list: [
                          { text: 'Item 1', href: 'item1.com' }
                        , { text: 'Item 2', href: 'item2.com' }
                        , { text: 'Item 3', href: 'item3.com' }
                    ]
            }
}

Helpers will be discussed in details in next documentation section - 'Helper Functions'.

Placeholders

Template placeholders can contain data-source and actions separated by ':'. Data-source is a field of the data object used for the placeholder. Actions describe how the data should be decorated. Action is a list of operations separated by comma. Result from the first action is going as a argument to the second and so on. Executetion of actions is from right to left. Actions are optional.

`{{ name : act2, act1 }}`
// placeholder should take data from field 'name', execute 'act1' and 'act2' over it
// actions are separated by ',' and are executed from right to left

`{{ list : li, a }}`
// take data from 'list' and render each element first with 'a' then with 'li' actions

`{{ name }}` // render data from 'name'. Only data is provided to this placeholder
`{{ :someAction}}` // no data, but the result of the action will fill the placeholder
`{{ @all : someAction }}` // provide all the data to the action 'someAction'

Actions

Actions are concise representations of a sequence of function calls. Some functions pertain to data manipulation, others to rendering, and some to mixing. We use a prefix system for enhanced readability and maintainability.

  • Render functions are most used so they don't have any prefix;
  • Data functions start with '>';
  • Mixing functions start with '[]';
  • Conditional render actions start with '?';
  • Extended render start with '+';

Here are some examples:

`
{{ : li }} // example for render actions
{{ : >setup}} // example for data actions
{{ friends : []coma }} // example for mixing action
{{ list : ul, [], li, a}} // example with render and mixing actions
`
// NOTE: See that mixing function has no name after the prefix. 
// Anonymous mixing is a build in function that will do -> resultList.join ( '' )
// The data will be rendered with 'a', then with 'li'
// then all 'li' elements will be merged and will be provided to 'ul'

When input data is array, the result will be an array. Result for each element will stay separated until come the mixing function.

Learn more about how actions work in the section 'helper functions' below.

Links

Credits

'@peter.naydenov/morph' was created and supported by Peter Naydenov.

License

'@peter.naydenov/morph' is released under the MIT License.