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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lytical/jxf

v1.0.2

Published

A TypeScript library for transforming template declarations into formatted strings based on provided data.

Downloads

297

Readme

@lytical/jxf

JXF (short for JavaScript Tranformation) library provides a similar solution that XSLT provides, for plain old data (POD) JavaScript objects.
Using JSPath for XPATH like DSL, declare transformation templates with declarative conditional statements, to transform your objects into a text formatted document.

This lightweight implementation is extendable to support simple to complex transformation.

Among other use cases...

  • Use it to automate document-driven business processes.
  • Dynamically render content for emails; web pages; code generation.
  • Utilize it for EDI processing.

Built for TypeScript, you can utilize the library with plain old JavaScript.

Supports ES6 environments in both DOM and NodeJS.

Getting Started

After installing JXF, import and invoke the jxf() function. DSL usage documentation can be found in JSPath.

Please note: The current version of (@types/[email protected]) is outdated and does not properly exports the default apply() function. Until this is corrected, you must npm install -D @types/jspath as a dev dependency to avoid TypeScript compile errors. see: https://www.npmjs.com/package/@types/jspath

Usage

jxf(data, transforms, [variables]) 

Where

| argument | description | | --- | --- | | data | an object or array | | transforms | an array of one or more transformers and strings | | variables | an optional object with keys are variable names and respective values. | | returns | an array for strings you can concatenate to compose any text document. |

Example

Let's say you want to create the following markdown...

Markdown

Thank you for your interest in our products. As discussed, the following are the top (2) products you are interested in.

| Product | Description | Cost | | --- | --- | ---: | | CRM | Our state-of-the-art Customer Relationship Management | $39 / mo | | CMS | Build web applications and sites with No Coding required | $2500 / yr |

Let me know when you want to move forward...

Regards,

Sally Salesperson
[email protected]

Source Code

Import jxf:

import jxf from '@lytical/jxf';

Using the following data:

const data = {
  customer: {
    first_name: 'Barry',
    last_name: 'Hayles',
    email: '[email protected]',
  },
  product: [
    {
      name: 'CRM',
      description: 'Our state-of-the-art Customer Relationship Management',
      price: 39.0,
      term: 'monthly',
    },
    {
      name: 'CMS',
      description:
        'Build web applications and sites with No Coding required',
      price: 2500.0,
      term: 'yearly',
    },
  ],
  sales_rep: {
    name: 'Sally Salesperson',
    email: '[email protected]',
  },
};

...and with the following transformation:

const transform = [
  `Hi `,
  jxf_value_of('.customer.first_name'),
  `, 

Thank you for your interest in our products. As discussed, the following are the top (`,
  jxf_length('.product'),
  `) products you are interested in.

| Name | Description | Cost |
| --- | --- | ---: |
`,
  jxf_for_each('.product', [
  `| `,
  jxf_value_of('.name'),
  ` | `,
  jxf_value_of('.description'),
  ` | $`,
  jxf_value_of('.price'),
  ` / `,
  jxf_switch('.term', [
    jxf_case('.{. === "monthly"}', ['mo']),
    jxf_case('.{. === "yearly"}', ['yr']),
  ]),
  ` |
`,
  ]),
  `

Let me know when you want to move forward... 

Regards, 

`,
  jxf_value_of('.sales_rep.name'),
  `\\
`,
  jxf_value_of('.sales_rep.email'),
];

...perform the transformation:

const rs = jxf(data, transform);
const message = rs.join('');
console.log(message);

Documentation

A transformers takes as an argument (at the minimum), a selector string (to match the target data). (e.g. '.property{. > 1.25}')

Creating a custom transformer involves returning function with the following signature: (data, ctx) => string[]

import apply from 'jspath';

import type { jxf_transformer_t } from '@lytical/jxf/types';

export function my_custom_xformer(match: string): jxf_transformer_t {
  return (data, ctx): string[] => {
    const [val] = apply(match, data, ctx);
    return [val?.toString() ?? ''];
  };
}

data is the javascript type to select (match) and transform to an array of string. ctx stores variables. Variable should be considered immutable within the context.

This library has standard transformers;

import { ... } from '@lytical/jxf';

Transformers

*jxf_value_of(match, [formatter])


Transforms a single scalar value to a string.

| Argument | Description | | --- | --- | | match | The selector to match the scalar value. | | formatter | An optional callback function to specialize the formatting of the scalar value; (val: any) => string

* jxf_variable(name, match)


Set a variable name with selected (matched) data. This is useful in capturing values in outer for loops, to be used in inner for loops.

| Argument | Description | | --- | --- | | name | The variable name. | match | The selector to match the variable value. |

Note: variable names starting with $ are reserved.

Access the variables in your select (match) statement by prefixing the name with $. (e.g. '.user{.age < $max_age}')

* jxf_with(match, transformers)


Select (match) data used in nested transformations.

| Argument | Description | | --- | --- | | match | The selector to match the scalar value. | | transformers | An array of transformers to process the selected data.

* jxf_length(match)


Transforms a selected array's length. The following will not select the product array length .product.length.
This statement will try to select the length property of the element(s) of the product array.

| Argument | Description | | --- | --- | | match | The selector to match the array. |

* jxf_if(match, transformers)


Execute the nested transformations if the selected (matched) value is truthy.

| Argument | Description | | --- | --- | | match | The selector to match the value, and test for truthyness. | | transformers | An array of transformers to process the data in context if the match is truthy.

* jxf_switch(match, transformers)


Transforms a single scalar value to a string.

| Argument | Description | | --- | --- | | match | The selector to match the value to switch. | | transformers | An array of jxf_case() transformers to test the matched value. (Note: any type of transformer can be added here, but this should be last in the array to handle a default case.)

* jxf_case(match, transformers)


Used as nested transformers to jxf_switch(), that are executed if the match case is truthy.

| Argument | Description | | --- | --- | | match | The selector to test the switched value. | | transformers | An array of transformers to process the data in context if the match is truthy.

* jxf_for_each(match, transformers, [sort])


Execute the nested transformers for each item in a selected array.

| Argument | Description | | --- | --- | | match | The selector to match the array value. | | transformers | An array of transformers to process each item in the matched array.

For each array item, the following variables are available.

| Name | Description | | --- | --- | | $even | true if the array item is in an even position | | $first | true if the array item is first | | $last | true if the array item is last | | $length | the length of the array | | $odd | true if the array item is in an odd position | | $parent | the outer data |

* jxf_for_keys(match, transformers, [sort])


Execute the nested transformers for each key in a selected object.

| Argument | Description | | --- | --- | | match | The selector to match the first object value. | | transformers | An array of transformers to process each key in the matched object.

Stay tuned! I have more packages to come.`

lytical(r) is a registered trademark of lytical, inc. all rights are reserved.