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

organic-formatter

v1.0.2

Published

String formatting library

Downloads

4

Readme

Intro

This template engine can be used to format file names or any other required string values depending on a set of some values. The language itself is not complicated, and in most aspects is similar to many other template languages. Input consist of text and blocks surrounded by curly braces. Inside these brackets you can refer to variables or call functions (built-in or user-defined). When template is evaluated, these blocks are replaced with resolved values. The simplest example of a template is a variable name written in curly braces. Such block will be replaced with computed value of the variable you've written. For example:

/home/user/books/{author} - {title}.pdf

after evaluation can become:

/home/user/books/J. R. R. Tolkien - Silmarillion.pdf

There are some more advanced features the engine can offer.

Installing

npm install --save organic-formatter

Usage

const formatter = require('organic-formatter');

let propsObj = {
  'var': 'some value',
  UC_var: 'some value',
  uc: 'SOME VALUE',
  empty: '',
  obj: {
    prop: 'prop value'
  },
  arr: ['first', 'second', 'third']
};

const processor = new formatter.TemplateProcessor(formatter.createPropsResolver(dataObject));
await processor.process('{uc|lowercase}'); // results in 'some value'

Filters

You can process any variable with a set of filters. For example, { title | lowercase } — converts book's title to lowercase. You can add as many filters as you want, separating them with | character. Whitespaces do not matter.

{author|lowercase|trim}

Filters are applied in the order they are listed in a block, from the leftmost to the rightmost. Each filter is a mere function and can receive other arguments that you can list in round brackets after function name. For example: { series_index | pad_left(3, '0') } will be evaluated as 007 if series_index is 7. Here you process series_index with a filter pad_left which is a function getting exactly three arguments, first being the processed string (or output of the previous filter in chain). This function gets a string and, if the string is shorter than some required length, pads it with some character from the left for it to have minimum length. First argument is the resolved value of series_index. Second one is minimal length of string we want to get. Third one is a string which be used to pad value if it is shorted than required. Each filter gets a result of previous filter in chain as its first argument. If filter is the first one in the chain (right after the variable, as pad_left in the example above) it gets resolved value of the variable instead. A very first value in a block (in most cases, the value of the variable you write right after opening a block) is called a head value of a block.

Strings

Strings that you pass to functions must be wrapped in single or double quotes. Inside these strings you can use a limited set of escape sequences to mention special characters. For example, if you need to include a single quote inside your string, you cannot do it directly, as it will close string literal instead. You should prepend this quote with backslash character as in the following example:

{ title | wrap('\'@\'') } — will wrap `title` in single quotes.

Backslash itself also should be escaped (write \ whenever you want a string with a backslash).

Only \ ' " \n \r \t \b sequences can be used. Any other escape sequence is not supported and will trigger an error while parsing the template.

Numbers

You can use integer numbers too. No floating-point numbers are supported. Although a function can get a string with floating number and parse it to use this number. Numbers and strings are interchangeable. You can use a number instead of a string and vise versa. You can wrap a number in quotes where function expects a number, and write your string without quotes if it represents a number. Everything will work fine. We've used pad_left function as a filter before, and have wrote it in this way:

{ series_index | pad_left(3, '0') }

But you could write it in this way too:

{ series_index | pad_left(3, 0) }

There will be no error. Template engine internally converts numbers to strings before passing them to functions. A function should parse a string if it wants a number, and use the parsed value if required.

Nested calls

You can use a result of another function as an argument. Example:

{ author | func(func2(a), b) }

Identifiers and specifiers

Variables and functions names are identifiers. An identifier consists of latin alphabetic characters, digits and some other characters: _ . @ # Only letter or underscore can be the first character of an identifier. The hash character (#) has special meaning for variable names. It should not be used in function names, but this rule is not enforced. Hash divides an identifier into two parts: one before the hash is actual name of a variable, one after the hash is called specifier. An specifier modifies the process of resolving a variable. How specifier is interpreted depends on a resolver. For example, a specifier can be used to access a specified element of an array. { tag#2 } will be resolved to second element of the array of tags. Different resolvers can offer another meanings for specifiers.

Optional blocks

There can be a question mark in the beginning of a block. It means that if the first resolved value of the block is an empty string, resolving process should stop and do not apply any other filters to this empty string. It can be useful, for example, when you want some value to be surrounded with some text, but only if the value exists. Using such code: {var|wrap('[@]')} produces two brackets without any text between them if var is resolved to an empty string. But using the following code: {?var|wrap('[@]')} is this case produces nothing and will be evaluated to an empty string itself when 'var' is empty.

Function calls

When function is called without arguments, you can omit braces. But you can also write it, it changes nothing. For example, two following examples are totally equivalent: {var|lowercase} and {var|lowercase()}

Variable resolving

Variables are resolved to its values by resolvers. A resolver can either resolve a variable or not. A resolver fails to resolve a variable, for example, if it knows nothing about it (but another resolve can use a some default value instead). In this case variable is considered to be an empty string. For example, if there is no variable named gopher, the following template:

Look, here is a gopher: {gopher}. Did you see it?

will be evaluated to the following string:

Look, here is a gopher: . Did you see it?

Yeah, you didn't see the gopher. Me too. But it does exist. It was evaluated to an empty string. Such behavior can be helpful in most cases, but you can set a strictVarResolve flag on TemplateProcessor and any variable that cannot be resolved will result in an error. So you will not be able to evaluate this template at all.

When you write an identifier without braces, it can be interpreter either as a variable or a function call without arguments. It is unwanted situation when variable name collates with a name of a function, but you should know that variable will be tried first. If all resolves will fail to resolve a variable, it will be considered to be a function call. If there is no function too, the identifier will not be resolved and will result in either considering it to be an empty string or throwing an error (if strictVarResolve flag is set).

Function result as the first variable

You can use a function instead of a plain variable to get a head value of a block. Just write it:

{ generate_some_value(123) | lowercase }

Custom block markers

You can set custom markers denoting start and end of blocks. For example:

const processor = new formatter.TemplateProcessor(formatter.createPropsResolver(/* ... */), false, {
  openBlockMarker: "%<",
  closeBlockMarker: ">%"
});
processor.process("%< author >%");

Built-in functions

lowercase

upppercase

trim

def --- if first argument is empty, returns some other value instead

propercase --- converts string to proper case (ex., thIs is some title -> This is Some Title)

add --- converts arguments to numbers are sums them

sub

wrap --- outputs its second argument, replacing @ symbol with the value of first argument

_lorem --- outputs n words of lorem ipsum

list --- takes arguments and converts them to list

join --- joins list items with separator

now --- returns current date

format_date --- formats date using moment.js

format_num --- formats number using numeral library.

Custom functions

You can add your own functions to template processor.

processor.addFuncResolver("function_name", (a, b) => a + b);

Callback arguments can be values of any type.