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

@gershy/util-jsfn-encode

v0.0.22

Published

TODO

Readme

Jsfn

An encoding format especially geared for replicating functions and classes across javascript processes. It's called jsfn because it's json plus functions! Pronounce it in two syllables: "jayce-fun".

Code and code references

Encoding a jsfn value results in an object with code and jsImports properties:

import jsfnEncode from '@gershy/util-jsfn-encode';

const { code, jsImports } = jsfnEncode({
  baseUrl: import.meta.url,
  val: {
    desc: 'my custom object',
    fn: () => console.log('I am the custom object')
  }
});

console.log(code);
// Outputs a string representing encoded jsfn:
//  | `{
//  |   desc: 'my custom object',
//  |   fn: () => console.log('I am the custom object')
//  | }`

// This string can be decoded with a simple `eval` call:
const obj = eval(code);
obj.fn(); // Prints 'I am the custom object'

Note that jsfnEncode'd values must be decodable in any @gershy context! For this to be possible, every nested value in the jsfnEncode call must be either (1) a valid json value, or (2) a sovereign class or function.

Sovereign functions

A sovereign function (or class) has no dependencies other than its own parameters, and the javascript global resolution context.

The "javascript global resolution context" is the sum of:

  1. the subset of all javascript globals that are widely supported in all common, modern environments - including, e.g., TextDecoder, and excluding, e.g., process (which is unique to nodejs)
  2. the clearing / cl globals from @gershy/clearing, what are considered defacto globals that pre-exist anywhere jsfn is used

Sovereign functions also must not reference meta-properties such as import.meta.

Some non-sovereign functions:

const val = 'hello';

// References local, outside-of-scope variable `val`
const notSovereign1 = () => console.log(val);

// References nodejs-specific `Buffer`
const notSovereign2 = (base64: string) => Buffer.from(v, 'base64').toString('utf8');

A sovereign function:

// Only references its parameter, and `Math` from the global resolution context
const sovereign = (val: string) => Math.max(50, val.length);

A sovereign function pretending to import another script (in this case, @gershy/phrasing)

const sovereign = (inp: { jsfnImport: (val: string) => any, parts: string[] }) => {
  
  // References nothing other than its parameters, and `cl` from @gershy/clearing - note that
  // specifically @gershy/clearing is considered, within the context of jsfn, to be a dependable
  // member of the "global resolution context"!
  
  const { default: ph } = inp.jsfnImport('@gershy/phrasing') as typeof import('@gershy/phrasing');
  
  return String[cl.baseline](`
    | You gave me some parts, that is, an array of strings.
    | Now I shall formulate a camel case value from them.
    | Here it is: "${ ph('parts->camel', inp.parts) }"
  `);
  
};

Oh actually...

Sovereign functions can import other scripts!

When jsfnEncode encodes a function or class, it scans sourcecode for occurrences of the form:

  • const xxx = yyy.jsfnImport('zzz')
  • const { xxx1, xxx2: { xxx3 } } = yyy.jsfnImport('zzz')
  • const [ xxx1, xxx2 ] = yyy.jsfnImport('zzz')
  • Any other destructuring assignment, followed by the jsfnImport call.

When jsfnEncode encodes, it will delete any such occurrences from the function/class sourcecode, interpret the occurrence, and populate its jsImports return property:


const sovereign = (inp: { jsfnImport: (val: string) => any, parts: string[] }) => {
  
  // References nothing other than its parameters, and `cl` from @gershy/clearing
  
  const { default: ph } = inp.jsfnImport('@gershy/phrasing') as typeof import('@gershy/phrasing');
  
  return String[cl.baseline](`
    | You gave me some parts, as in, an array of strings.
    | Now I shall formulate a camel case value from them.
    | Here it is: "${ ph('parts->camel', inp.parts) }"
  `);
  
};
const { code, jsImports } = jsfnEncode({
  baseUrl: import.meta.url,
  val: sovereign
});

console.log(code);
// Outputs a string representing the function with the `jsfnImport` line stripped - note the `ph`
// reference is dangling!
//  | inp => {
//  |   
//  |   return String[cl.baseline](`
//  |     | You gave me some parts, as in, an array of strings.
//  |     | Now I shall formulate a camel case value from them.
//  |     | Here it is: "${ ph('parts->camel', inp.parts) }"
//  |   `);
//  |   
//  | }

console.log(jsImports);
// The `jsImports` value is populated; it tracks what imports are needed for `code` to be decodable
// and covers the dangling reference in `code`
//  | [
//  |   {
//  |     importPath: '@gershy/phrasing',
//  |     varDef: '{default:ph}'            // Note this is a *string*!!
//  |   }
//  | ]

Note that for yyy.jsfnImport('zzz'), zzz may be an npm module name, any global url resolving to ts/js, or a relative filepath. If it's a relative filepath it's resolved against the baseUrl input property passed to jsfnEncode. Note a simple pattern can almost always be used: pass import.meta.url to baseUrl, and use the same relative filepath you would in a normal top-level import.

More effort is shifted to the decoding step when code contains jsfnImports. For example, to decode arbitrary jsfn with imports a very coarse approach (there are subtle bugs here!) to produce runnable cjs could look like:

import { type JsImport } from '@gershy/util-jsfn-encode'; // type JsImport = { importPath: string, varDef: null | string };

const decodeReferentialJsfn = (jsfn: { code: string, jsImports: JsImport[] }) => eval([
  
  `require('@gershy/clearing')`, // In case clearing globals aren't already installed
  
  // Add in `eval`-able `require` calls for every js import
  ...jsImports.map(jsImport => {
    
    return jsImport.varDef
      ? `const ${ jsImport.varDef } = require('${ jsImport.importPath }')`
      :                              `require('${ jsImport.importPath }')`
    
  }),
  
  // Now dangling references throughout `code` are satisfied by the import `const` definitions
  code
  
].join(';'));

Also...

Any object can be jsfn-encoded!

Attach a toJsfn method. TODO: Should probably make this a symbol...