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

@jackens/nnn

v2026.4.15

Published

Jackens’ JavaScript helpers.

Readme

nnn

A collection of Jackens’ JavaScript helper utilities (version: 2026.4.15).

Installation

bun i @jackens/nnn

or

npm i @jackens/nnn

Usage

import {
  c,
  csvParse,
  fixPlTypography,
  h,
  hasOwn,
  isArray,
  isFiniteNumber,
  isInteger,
  isNumber,
  isRecord,
  isString,
  jsOnParse,
  monokai,
  nanolightTs,
  newEscape,
  newNounForm,
  newTokenizer,
  omit,
  pick,
  rwd,
  s,
  svgUse,
  uuidV1,
  vivify,
} from '@jackens/nnn' // or './node_modules/@jackens/nnn/nnn.js'

Exports

  • CNode: Represents a CSS rule node for the c helper.
  • CRoot: Represents the root CSS object for the c helper.
  • HArgs: Tuple argument type for the h and s helpers.
  • HArgs1: Single argument type for the h and s helpers.
  • c: A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
  • csvParse: Parses a CSV string into a two-dimensional array of strings.
  • fixPlTypography: Applies Polish-specific typographic corrections to a DOM subtree.
  • h: A lightweight HyperScript-style helper for creating and modifying HTMLElements (see also s).
  • hasOwn: Checks whether an object has the specified key as its own property.
  • isArray: Checks whether the argument is an array.
  • isFiniteNumber: Checks whether the argument is a finite number (excludes ±Infinity and NaN).
  • isInteger: Checks whether the argument is an integer number.
  • isNumber: Checks whether the argument is of type number (includes NaN and ±Infinity).
  • isRecord: Checks whether the argument is a plain object (not null and not an array).
  • isString: Checks whether the argument is a string.
  • jsOnParse: Parses JSON with support for handler-based value transformation (“JavaScript ON”).
  • monokai: A Monokai-inspired color scheme for use with the c helper and nanolightTs tokenizer.
  • nanolightTs: A TypeScript/JavaScript syntax highlighting tokenizer built using newTokenizer.
  • newEscape: Creates a tag function for escaping interpolated values in template literals.
  • newNounForm: Creates a function that returns the appropriate noun form based on a numeric value using Intl.PluralRules.
  • newTokenizer: A helper for building simple tokenizers (see also nanolightTs).
  • omit: Creates a new object excluding the specified keys from the source object.
  • pick: Creates a new object containing only the specified keys from the source object.
  • rwd: A responsive web design helper that generates CSS rules for a grid-like layout.
  • s: A lightweight HyperScript-style helper for creating and modifying SVGElements (see also h).
  • svgUse: Shorthand for creating an SVG element with a <use> child referencing an icon by ID.
  • uuidV1: Generates a UUID v1 (time-based) identifier.
  • vivify: A Proxy-based helper for auto-vivification of nested object structures.

CNode

type CNode = {
    [attributeOrSelector: string]: string | number | CNode | undefined;
};

Represents a CSS rule node for the c helper. Keys are CSS properties or nested selectors.

CRoot

type CRoot = Record<PropertyKey, CNode>;

Represents the root CSS object for the c helper. Keys are top-level selectors or at-rules.

HArgs

type HArgs = [string | Node, ...HArgs1[]];

Tuple argument type for the h and s helpers.

HArgs1

type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs;

Single argument type for the h and s helpers.

c

const c: (root: CRoot, splitter?: string) => string;

A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.

root

An object describing CSS rules. Keys are selectors or at-rules; values are either CSS property values or nested rule objects.

splitter

A delimiter used to create unique keys (default: '$$'). The substring from splitter to the end of a key is ignored (e.g., src$$1src).

Returns

A CSS string representing the compiled rules.

Remarks

  • Keys whose values are primitives (string | number) are treated as CSS properties.
  • In property keys, uppercase letters become lowercase with a - prefix (e.g., fontFamilyfont-family); underscores become hyphens (e.g., font_familyfont-family).
  • Comma-separated selector keys expand into multiple selectors (e.g., { div: { '.a,.b': { margin: 1 } } }div.a,div.b{margin:1}).
  • Top-level keys starting with @ (at-rules) are not concatenated with child selectors.

Usage Examples

const actual1 = c(
  {
    a: {
      color: 'red',
      margin: 1,
      '.c': { margin: 2, padding: 2 },
      padding: 1,
    },
  },
)

const expected1 = `
a{
  color:red;
  margin:1
}
a.c{
  margin:2;
  padding:2
}
a{
  padding:1
}`.replace(/\n\s*/g, '')

expect(actual1).to.equal(expected1)

const actual2 = c(
  {
    a: {
      '.b': {
        color: 'red',
        margin: 1,
        '.c': { margin: 2, padding: 2 },
        padding: 1,
      },
    },
  },
)

const expected2 = `
a.b{
  color:red;
  margin:1
}
a.b.c{
  margin:2;
  padding:2
}
a.b{
  padding:1
}`.replace(/\n\s*/g, '')

expect(actual2).to.equal(expected2)

const actual3 = c(
  {
    '@font-face$$1': {
      fontFamily: 'Jackens',
      src$$1: 'url(otf/jackens.otf)',
      src$$2: "url(otf/jackens.otf) format('opentype')," +
      "url(svg/jackens.svg) format('svg')",
      font_weight: 'normal',
      'font-style': 'normal',
    },
    '@font-face$$2': {
      font_family: 'C64',
      src: 'url(fonts/C64_Pro_Mono-STYLE.woff)',
    },
    '@keyframes spin': {
      '0%': { transform: 'rotate(0deg)' },
      '100%': { transform: 'rotate(360deg)' },
    },
    div: {
      border: 'solid red 1px',
      '.c1': { 'background-color': '#000' },
      ' .c1': { background_color: 'black' },
      '.c2': { backgroundColor: 'rgb(0,0,0)' },
    },
    '@media(min-width:200px)': {
      div: { margin: 0, padding: 0 },
      span: { color: '#000' },
    },
  },
)

const expected3 = `
@font-face{
  font-family:Jackens;
  src:url(otf/jackens.otf);
  src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
  font-weight:normal;
  font-style:normal
}
@font-face{
  font-family:C64;
  src:url(fonts/C64_Pro_Mono-STYLE.woff)
}
@keyframes spin{
  0%{
    transform:rotate(0deg)
  }
  100%{
    transform:rotate(360deg)
  }
}
div{
  border:solid red 1px
}
div.c1{
  background-color:#000
}
div .c1{
  background-color:black
}
div.c2{
  background-color:rgb(0,0,0)
}
@media(min-width:200px){
  div{
    margin:0;
    padding:0
  }
  span{
    color:#000
  }
}`.replace(/\n\s*/g, '')

expect(actual3).to.equal(expected3)

const actual4 = c(
  {
    a: {
      '.b,.c': {
        margin: 1,
        '.d': {
          margin: 2,
        },
      },
    },
  },
)

const expected4 = `
a.b,a.c{
  margin:1
}
a.b.d,a.c.d{
  margin:2
}`.replace(/\n\s*/g, '')

expect(actual4).to.equal(expected4)

const actual5 = c(
  {
    '.b,.c': {
      margin: 1,
      '.d': {
        margin: 2,
      },
    },
  },
)

const expected5 = `
.b,.c{
  margin:1
}
.b.d,.c.d{
  margin:2
}`.replace(/\n\s*/g, '')

expect(actual5).to.equal(expected5)

const actual6 = c(
  {
    '.a,.b': {
      margin: 1,
      '.c,.d': {
        margin: 2,
      },
    },
  },
)

const expected6 = `
.a,.b{
  margin:1
}
.a.c,.a.d,.b.c,.b.d{
  margin:2
}`.replace(/\n\s*/g, '')

expect(actual6).to.equal(expected6)

csvParse

const csvParse: (csv: string, separator?: string) => string[][];

Parses a CSV string into a two-dimensional array of strings.

Supports quoted fields with escaped double quotes (""). Carriage returns are normalized.

csv

The CSV string to parse.

separator

The field delimiter (default: ',').

Returns

A 2D array where each inner array represents a row of fields.

Usage Examples

const text = `"aaa
""aaa""
aaa",bbb, "ccc,ccc"
"xxx,xxx", "yyy
yyy",zzz
 42 , "42" , 17

`

expect(csvParse(text)).to.deep.equal(
  [
    ['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
    ['xxx,xxx', 'yyy\nyyy', 'zzz'],
    [' 42 ', '42', ' 17'],
  ],
)

fixPlTypography

const fixPlTypography: (node: Node) => void;

Applies Polish-specific typographic corrections to a DOM subtree.

This function prevents orphaned conjunctions (single-letter words like “a”, “i”, “o”, “u”, “w”, “z”) from appearing at the end of a line by wrapping them with the following word in a non-breaking span. It also inserts zero-width spaces after slashes and dots to allow line breaks.

node

The root DOM node to process. All descendant text nodes are corrected recursively, except those inside IFRAME, NOSCRIPT, PRE, SCRIPT, STYLE, or TEXTAREA elements.

Usage Examples

const p = h('p',
  'Pchnąć w tę łódź jeża lub ośm skrzyń fig ' +
  '(zob. https://pl.wikipedia.org/wiki/Pangram).',
  ['br'],
  ['b', 'Zażółć gęślą jaźń.'],
)

fixPlTypography(p)

expect(p.innerHTML).to.deep.equal(
  'Pchnąć ' +
  '<span style="white-space:nowrap">w </span>' +
  'tę łódź jeża lub ośm skrzyń fig ' +
  '(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/' +
  '\u200Bwiki/\u200BPangram).' +
  '<br>' +
  '<b>Zażółć gęślą jaźń.</b>')

h

const h: {
    <T extends keyof HTMLElementTagNameMap>(tag: T, ...args1: HArgs1[]): HTMLElementTagNameMap[T];
    <N extends Node>(node: N, ...args1: HArgs1[]): N;
    (tagOrNode: string | Node, ...args1: HArgs1[]): Node;
};

A lightweight HyperScript-style helper for creating and modifying HTMLElements (see also s).

tagOrNode

If a string, it is treated as the tag name for a new element. If a Node, that node is modified in place.

args

Additional arguments processed as follows:

  • Object: maps attributes/properties. Keys starting with $ set element properties (without the $ prefix); other keys set attributes via setAttribute. A value of false removes the attribute.
  • null/undefined: ignored.
  • Node: appended as a child.
  • string/number: converted to a Text node and appended.
  • HArgs array: processed recursively.

Returns

The created or modified HTMLElement.

Usage Examples

const b = h('b')

expect(b.outerHTML).to.equal('<b></b>')

const i = h('i', 'text')

h(b, i)

expect(i.outerHTML).to.equal('<i>text</i>')
expect(b.outerHTML).to.equal('<b><i>text</i></b>')

h(i, { $className: 'some class' })

expect(i.outerHTML)
  .to.equal('<i class="some class">text</i>')
expect(b.outerHTML)
  .to.equal('<b><i class="some class">text</i></b>')

expect(h('span', 'text').outerHTML)
  .to.equal('<span>text</span>')
expect(h('span', { $innerText: 'text' }).outerHTML)
  .to.equal('<span>text</span>')

expect(h('span', '42').outerHTML)
  .to.equal('<span>42</span>')
expect(h('span', 42).outerHTML).to.equal('<span>42</span>')

expect(h('div', { style: 'margin:0;padding:0' }).outerHTML)
  .to.equal('<div style="margin:0;padding:0"></div>')
expect(h('div', { $style: 'margin:0;padding:0' }).outerHTML)
  .to.equal(
    '<div style="margin: 0px; padding: 0px;"></div>',
  )
expect(
  h(
    'div',
    { $style: { margin: 0, padding: 0 } },
  ).outerHTML,
).to.equal('<div style="margin: 0px; padding: 0px;"></div>')

const input1 = h('input', { value: 42 })
const input2 = h('input', { $value: '42' })

expect(input1.value).to.equal('42')
expect(input2.value).to.equal('42')

expect(input1.outerHTML).to.equal('<input value="42">')
expect(input2.outerHTML).to.equal('<input>')

const checkbox1 = h(
  'input',
  { type: 'checkbox', checked: true },
)
const checkbox2 = h(
  'input',
  { type: 'checkbox', $checked: true },
)

expect(checkbox1.checked).to.be.true
expect(checkbox2.checked).to.be.true

expect(checkbox1.outerHTML)
  .to.equal('<input type="checkbox" checked="">')
expect(checkbox2.outerHTML)
  .to.equal('<input type="checkbox">')

const div = h('div')

expect(div.key).to.be.undefined

h(div, { $key: { one: 1 } })

expect(div.key).to.deep.equal({ one: 1 })

h(div, { $key: { two: 2 } })

expect(div.key).to.deep.equal({ one: 1, two: 2 })

const elemWithClass = h('div', { class: 'test' })

expect(elemWithClass.getAttribute('class')).to.equal('test')

const elemWithText = h('div', 'initial')

h(elemWithText, ' more')
expect(elemWithText.outerHTML)
  .to.equal('<div>initial more</div>')

const elemWithNested = h('div',
  ['span', 'hello'],
  ['b', 'world'])

expect(elemWithNested.outerHTML)
  .to.equal('<div><span>hello</span><b>world</b></div>')

hasOwn

const hasOwn: (ref: unknown, key: unknown) => boolean;

Checks whether an object has the specified key as its own property.

A null-safe wrapper around Object.hasOwn.

ref

The object to check.

key

The property key to look for.

Returns

true if ref is not nullish and has key as an own property, false otherwise.

Usage Examples

const obj = { 42: null, null: 'k,e,y', 'k,e,y': 42 }

expect(42 in obj).to.be.true
expect(hasOwn(obj, 42)).to.be.true

expect('42' in obj).to.be.true
expect(hasOwn(obj, '42')).to.be.true

expect('null' in obj).to.be.true
expect(hasOwn(obj, 'null')).to.be.true

expect(null in obj).to.be.true
expect(hasOwn(obj, null)).to.be.true

expect('k,e,y' in obj).to.be.true
expect(hasOwn(obj, 'k,e,y')).to.be.true

expect(['k', 'e', 'y'] in obj).to.be.true
expect(hasOwn(obj, ['k', 'e', 'y'])).to.be.true

expect('toString' in obj).to.be.true
expect(hasOwn(obj, 'toString')).to.be.false

expect(() => 'key' in null).to.throw
expect(hasOwn(null, 'key')).to.be.false

expect(() => 'key' in undefined).to.throw
expect(hasOwn(undefined, 'key')).to.be.false

isArray

const isArray: (arg: unknown) => arg is unknown[];

Checks whether the argument is an array.

arg

The value to check.

Returns

true if arg is an array, false otherwise.

Usage Examples

expect(isArray([])).to.be.true

const fakeArray1 = Object.create({ constructor: Array })

expect(isArray(fakeArray1)).to.be.false

const fakeArray2 =
  Object.create({ [Symbol.toStringTag]: Array.name })

expect(isArray(fakeArray2)).to.be.false

isFiniteNumber

const isFiniteNumber: (arg: unknown) => arg is number;

Checks whether the argument is a finite number (excludes ±Infinity and NaN).

arg

The value to check.

Returns

true if arg is a finite number, false otherwise.

Usage Examples

expect(isFiniteNumber(42)).to.be.true
expect(isFiniteNumber(Number(42))).to.be.true
expect(isFiniteNumber(new Number(42))).to.be.false
expect(isFiniteNumber(NaN)).to.be.false
expect(isFiniteNumber(Infinity)).to.be.false

isInteger

const isInteger: (arg: unknown) => arg is number;

Checks whether the argument is an integer number.

arg

The value to check.

Returns

true if arg is an integer number, false otherwise.

Usage Examples

expect(isInteger(42)).to.be.true
expect(isInteger(42.00000000000001)).to.be.false
expect(isInteger(42.000000000000001)).to.be.true
// ^because of loss of precision
expect(isInteger(Number(42))).to.be.true
expect(isInteger(new Number(42))).to.be.false
expect(isInteger(NaN)).to.be.false
expect(isInteger(Infinity)).to.be.false

isNumber

const isNumber: (arg: unknown) => arg is number;

Checks whether the argument is of type number (includes NaN and ±Infinity).

arg

The value to check.

Returns

true if typeof arg === 'number', false otherwise.

Usage Examples

expect(isNumber(42)).to.be.true
expect(isNumber(Number(42))).to.be.true
expect(isNumber(new Number(42))).to.be.false
expect(isNumber(NaN)).to.be.true
expect(isNumber(Infinity)).to.be.true

isRecord

const isRecord: (arg: unknown) => arg is Record<PropertyKey, unknown>;

Checks whether the argument is a plain object (not null and not an array).

arg

The value to check.

Returns

true if arg is a plain object, false otherwise.

Usage Examples

expect(isRecord({})).to.be.true
expect(isRecord([])).to.be.false
expect(isRecord(Object.create(null))).to.be.true

const fakeNumber1 = Object.create({ constructor: Number })

expect(isRecord(fakeNumber1)).to.be.true

const fakeNumber2 =
  Object.create({ [Symbol.toStringTag]: Number.name })

expect(isRecord(fakeNumber2)).to.be.true

expect(isRecord(new Number(42))).to.be.true
expect(isRecord(new String('42'))).to.be.true

class FooBar { }

expect(isRecord(new FooBar())).to.be.true

isString

const isString: (arg: unknown) => arg is string;

Checks whether the argument is a string.

arg

The value to check.

Returns

true if typeof arg === 'string', false otherwise.

Usage Examples

expect(isString('42')).to.be.true
expect(isString(String('42'))).to.be.true
expect(isString(new String('42'))).to.be.false

jsOnParse

const jsOnParse: (handlers: Record<PropertyKey, Function>, text: string) => any;

Parses JSON with support for handler-based value transformation (“JavaScript ON”).

Objects with exactly one property whose key exists in handlers and whose value is an array are replaced by invoking the corresponding handler with the array elements as arguments.

handlers

An object mapping handler names to functions.

text

The JSON string to parse.

Returns

The parsed value with handler substitutions applied.

Usage Examples

const handlers = {
  $add: (a: number, b: number) => a + b,
  $hello: (name: string) => `Hello ${name}!`,
  $foo: () => 'bar',
}

const actual1 = jsOnParse(handlers, `[
  {
    "$add": [1, 2]
  },
  {
    "$hello": ["World"]
  },
  {
    "nested": {
      "$hello": ["nested World"]
    },
    "one": 1,
    "two": 2
  },
  {
    "$foo": []
  },
  {
    "$foo": ["The parent object does not have exactly one property!"],
    "one": 1,
    "two": 2
  }
]`)

expect(actual1).to.deep.equal(
  [
    3,
    'Hello World!',
    {
      nested: 'Hello nested World!',
      one: 1,
      two: 2,
    },
    'bar',
    {
      $foo: [
        'The parent object does not have ' +
        'exactly one property!',
      ],
      one: 1,
      two: 2,
    },
  ],
)

const actual2 = jsOnParse(
  { $notFunc: 'handler not being a function' } as any,
  '{"$notFunc": [1, 2]}',
)

expect(actual2).to.deep.equal({ $notFunc: [1, 2] })

const actual3 = jsOnParse(
  handlers,
  '{"$unknown_handler_key": [1, 2]}',
)

expect(actual3)
  .to.deep.equal({ $unknown_handler_key: [1, 2] })

const actual4 = jsOnParse(
  handlers,
  '{"$add": {"not": "array"}}',
)

expect(actual4)
  .to.deep.equal({ $add: { not: 'array' } })

monokai

const monokai: CRoot;

A Monokai-inspired color scheme for use with the c helper and nanolightTs tokenizer.

nanolightTs

const nanolightTs: (code: string) => HArgs1[];

A TypeScript/JavaScript syntax highlighting tokenizer built using newTokenizer.

code

The source code string to tokenize.

Returns

An array of HArgs1 elements suitable for rendering with h.

Usage Examples

const codeJs =
  'const answerToLifeTheUniverseAndEverything = ' +
  "{ 42: 42 }['42'] /* 42 */"

expect(nanolightTs(codeJs)).to.deep.equal(
  [
    ['span', { class: 'keyword-1' }, 'const'],
    ' ',
    ['span',
      { class: 'identifier-4' },
      'answerToLifeTheUniverseAndEverything',
    ],
    ' ',
    ['span', { class: 'operator' }, '='],
    ' ',
    ['span', { class: 'punctuation' }, '{'],
    ' ',
    ['span', { class: 'number' }, '42'],
    ['span', { class: 'operator' }, ':'],
    ' ',
    ['span', { class: 'number' }, '42'],
    ' ',
    ['span', { class: 'punctuation' }, '}'],
    ['span', { class: 'punctuation' }, '['],
    ['span', { class: 'string' }, "'42'"],
    ['span', { class: 'punctuation' }, ']'],
    ' ',
    ['span', { class: 'comment' }, '/* 42 */'],
  ],
)

newEscape

const newEscape: (escapeFn: (value: any) => string) => (template: TemplateStringsArray, ...values: unknown[]) => string;

Creates a tag function for escaping interpolated values in template literals.

escapeFn

A function that takes a value and returns its escaped string representation.

Returns

A tag function that escapes interpolated values using the provided escape map.

Usage Examples

const escapeFn = (value: any): string =>
  isArray(value)
    ? value.map(escapeFn).join(', ')
    : value === true || value === false
      ? `b'${+value}'`
      : value instanceof Date
        ? `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`
        : isFiniteNumber(value)
          ? `${value}`
          : isString(value)
            ? `'${value.replace(/'/g, "''")}'`
            : 'NULL'

const sql = newEscape(escapeFn)

const actual = sql`
  SELECT *
  FROM table_name
  WHERE column_name IN (
    ${[
      true,
      null,
      undefined,
      NaN,
      Infinity,
      42,
      '42',
      "4'2",
      /42/,
      new Date(323325000000),
    ]}
  )`

const expected = `
  SELECT *
  FROM table_name
  WHERE column_name IN (
    b'1', NULL, NULL, NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00'
  )`

expect(actual).to.equal(expected)

newNounForm

const newNounForm: (locale: string, forms: Partial<Record<Intl.LDMLPluralRule, string>>) => (value: number) => string;

Creates a function that returns the appropriate noun form based on a numeric value using Intl.PluralRules.

Different languages have different plural rules. The Intl.PluralRules API provides locale-aware plural category selection. Possible categories are:

  • zero: for zero items (used in some languages like Arabic, Latvian)
  • one: for singular (e.g., 1 item)
  • two: for dual (used in some languages like Arabic, Hebrew)
  • few: for small plurals (e.g., 2-4 in Polish)
  • many: for larger plurals (e.g., 5-21 in Polish)
  • other: fallback category (used by all languages)

locale

A BCP 47 language tag (e.g., pl, en).

forms

An object mapping plural categories to noun forms. Not all categories need to be provided; if a category is missing, the function falls back to other, then to an empty string.

Returns

A function that takes a numeric value and returns the appropriate noun form.

Usage Examples

const auto = newNounForm(
  'pl',
  { one: 'auto', few: 'auta', other: 'aut' },
)

expect(auto(0)).to.equal('aut')
expect(auto(1)).to.equal('auto')
expect(auto(17)).to.equal('aut')
expect(auto(42)).to.equal('auta')

const car = newNounForm('en', { one: 'car', other: 'cars' })

expect(car(0)).to.equal('cars')
expect(car(1)).to.equal('car')
expect(car(17)).to.equal('cars')
expect(car(42)).to.equal('cars')

const empty = newNounForm('en', {})

expect(empty(0)).to.equal('')
expect(empty(1)).to.equal('')
expect(empty(17)).to.equal('')
expect(empty(42)).to.equal('')

newTokenizer

const newTokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];

A helper for building simple tokenizers (see also nanolightTs).

decorator

A function that wraps each matched chunk. It receives the matched text (chunk) and optionally the metadata associated with the pattern that produced the match. For unmatched text between patterns, metadata is undefined.

specs

An array of tuples [metadata, pattern] where:

  • metadata: arbitrary data (e.g., a CSS class name) passed to decorator when the pattern matches.
  • pattern: a string or RegExp to match against the input.

Returns

A tokenizer function that accepts a code string and returns an array of decorated tokens.

Remarks

  1. Matches starting at an earlier position take precedence.
  2. Among matches at the same position, the longer one wins.
  3. Among matches of the same position and length, the one defined earlier wins.

Usage Examples

const tokenizer1 = newTokenizer(
  (chunk, metadata) => ({ chunk, metadata }),
  ['keyword', /\b(if|else|for)\b/],
  ['string', /"[^"]*"/],
)
const result1 = tokenizer1('if "hello" else "world"')

expect(result1).to.deep.equal(
  [
    { chunk: 'if', metadata: 'keyword' },
    { chunk: ' ', metadata: undefined },
    { chunk: '"hello"', metadata: 'string' },
    { chunk: ' ', metadata: undefined },
    { chunk: 'else', metadata: 'keyword' },
    { chunk: ' ', metadata: undefined },
    { chunk: '"world"', metadata: 'string' },
  ],
)

const tokenizer2 = newTokenizer(
  (chunk, metadata) => `${metadata}:${chunk}`,
  ['tag', 'BEGIN'],
  ['end', 'END'],
)
const result2 = tokenizer2('aBEGINbENDc')

expect(result2).to.deep.equal(
  [
    'undefined:a',
    'tag:BEGIN',
    'undefined:b',
    'end:END',
    'undefined:c',
  ],
)

const tokenizer3 = newTokenizer(
  (chunk) => chunk,
  ['test', /test/],
)
const result3 = tokenizer3('')

expect(result3).to.deep.equal([])

const tokenizer4 = newTokenizer(
  (chunk, metadata) => ({ chunk, metadata }),
  ['start', /^test/],
)
const result4 = tokenizer4('test here')

expect(result4).to.deep.equal(
  [
    { chunk: 'test', metadata: 'start' },
    { chunk: ' here', metadata: undefined },
  ],
)

const tokenizer5 = newTokenizer(
  (chunk, metadata) => metadata,
  ['later', /x/],
  ['earlier', /y/],
)
const result5 = tokenizer5('yx')

expect(result5).to.deep.equal(['earlier', 'later'])

const tokenizer6 = newTokenizer(
  (chunk) => chunk,
  ['short', 'a'],
  ['long', 'abc'],
)
const result6 = tokenizer6('abc')

expect(result6).to.deep.equal(['abc'])

const tokenizer7 = newTokenizer(
  (chunk) => chunk,
  ['empty', ''],
  ['word', /\w+/],
)
const result7 = tokenizer7('hello')

expect(result7).to.deep.equal(['hello'])

const tokenizer8 = newTokenizer(
  (chunk) => chunk,
  ['test', /xyz/],
)
const result8 = tokenizer8('abc')

expect(result8).to.deep.equal(['abc'])

const tokenizer9 = newTokenizer(
  (_chunk, metadata) => metadata,
  ['a', 'a'],
  ['b', 'b'],
)
const result9 = tokenizer9('aabb')

expect(result9).to.deep.equal(['a', 'a', 'b', 'b'])

omit

const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Omit<T, K>;

Creates a new object excluding the specified keys from the source object.

A runtime equivalent of TypeScript’s Omit<T, K> utility type. See also pick.

ref

The source object.

keys

An array of keys to exclude from the result.

Returns

A new object without the specified keys.

Usage Examples

const ref = { a: 42, b: '42', c: 17 }

expect(omit(ref, ['c'])).to.deep.equal({ a: 42, b: '42' })

pick

const pick: <T, K extends keyof T>(ref: T, keys: unknown[]) => Pick<T, K>;

Creates a new object containing only the specified keys from the source object.

A runtime equivalent of TypeScript’s Pick<T, K> utility type. See also omit.

ref

The source object.

keys

An array of keys to include in the result.

Returns

A new object with only the specified keys.

Usage Examples

const ref = { a: 42, b: '42', c: 17 }

expect(pick(ref, ['a', 'b'])).to.deep.equal(
  { a: 42, b: '42' },
)

rwd

const rwd: (root: CRoot, selector: string, cellWidthPx: number, cellHeightPx: number, ...specs: [number, number?, number?][]) => void;

A responsive web design helper that generates CSS rules for a grid-like layout.

root

The CSS root object to populate (see c).

selector

The CSS selector for the grid item.

cellWidthPx

The base cell width in pixels.

cellHeightPx

The base cell height in pixels.

specs

An array of breakpoint specifications, each a tuple of:

  • maxWidth: maximum number of cells per row (defines the viewport breakpoint).
  • width (optional, default 1): number of horizontal cells the element spans.
  • height (optional, default 1): number of vertical cells the element spans.

Usage Examples

const style: CRoot = {
  body: {
    margin: 0,
  },
  '.r6': {
    border: 'solid red 1px',
    '.no-border': {
      border: 'none',
    },
  },
}

rwd(style, '.r6', 200, 50, [6], [3], [1, 1, 2])

expect(style).to.deep.equal(
  {
    body: {
      margin: 0,
    },
    '.r6': {
      border: 'solid red 1px',
      '.no-border': {
        border: 'none',
      },
      boxSizing: 'border-box',
      display: 'block',
      float: 'left',
      width: '100%',
      height: '100px',
    },
    '@media(min-width:600px)': {
      '.r6': {
        width: 'calc(100% / 3)',
        height: '50px',
      },
    },
    '@media(min-width:1200px)': {
      '.r6': {
        width: 'calc(50% / 3)',
        height: '50px',
      },
    },
  },
)

s

const s: {
    <T extends keyof SVGElementTagNameMap>(tag: T, ...args1: HArgs1[]): SVGElementTagNameMap[T];
    <N extends Node>(node: N, ...args1: HArgs1[]): N;
    (tagOrNode: string | Node, ...args1: HArgs1[]): Node;
};

A lightweight HyperScript-style helper for creating and modifying SVGElements (see also h).

tagOrNode

If a string, it is treated as the tag name for a new element. If a Node, that node is modified in place.

args

Additional arguments processed as follows:

  • Object: maps attributes/properties. Keys starting with $ set element properties (without the $ prefix); other keys set attributes via setAttributeNS. A value of false removes the attribute.
  • null/undefined: ignored.
  • Node: appended as a child.
  • string/number: converted to a Text node and appended.
  • HArgs array: processed recursively.

Returns

The created or modified SVGElement.

Usage Examples

const XLINK_NS = 'http://www.w3.org/1999/xlink'

const svg1 = s('svg', { 'xlink:href': true })

expect(svg1.getAttributeNS(XLINK_NS, 'href')).to.equal('')

const svg2 = s('svg', { 'xlink:href': false })

expect(svg2.getAttributeNS(XLINK_NS, 'href')).to.be.null

const svg3 = s(
  'svg',
  { 'xlink:href': 'http://example.com' },
)

expect(svg3.getAttributeNS(XLINK_NS, 'href'))
  .to.equal('http://example.com')

const svg4 = s('svg', { 'xlink:title': 42 })

expect(svg4.getAttributeNS(XLINK_NS, 'title'))
  .to.equal('42')

svgUse

const svgUse: (id: string, ...args: HArgs1[]) => SVGSVGElement;

Shorthand for creating an SVG element with a <use> child referencing an icon by ID.

Equivalent to: s('svg', ['use', { 'xlink:href': '#' + id }], ...args).

id

The ID of the symbol to reference (without the # prefix).

args

Additional arguments passed to the outer <svg> element.

Returns

An SVGSVGElement containing a <use> element.

Usage Examples

const XLINK_NS = 'http://www.w3.org/1999/xlink'

const svg = svgUse('icon-home')

expect(svg.children.length).to.equal(1)

const useElement = svg.children[0]

expect(useElement.getAttributeNS(XLINK_NS, 'href'))
  .to.equal('#icon-home')

const svgWithViewBox =
  svgUse('icon-star', { viewBox: '0 0 24 24' })

expect(svgWithViewBox.getAttribute('viewBox'))
  .to.equal('0 0 24 24')

const useViewBox = svgWithViewBox.children[0]

expect(useViewBox.getAttributeNS(XLINK_NS, 'href'))
  .to.equal('#icon-star')

const svgWithClass =
  svgUse('icon-menu', { class: 'icon-btn' })

expect(svgWithClass.getAttribute('class'))
  .to.equal('icon-btn')

expect(svgWithClass.children.length).to.equal(1)

const useClass = svgWithClass.children[0]

expect(useClass.getAttributeNS(XLINK_NS, 'href'))
  .to.equal('#icon-menu')

const svgWithMultipleAttrs = svgUse(
  'icon-settings',
  { width: 24, height: 24, class: 'icon' },
)

expect(svgWithMultipleAttrs.getAttribute('width'))
  .to.equal('24')

expect(svgWithMultipleAttrs.getAttribute('height'))
  .to.equal('24')

expect(svgWithMultipleAttrs.getAttribute('class'))
  .to.equal('icon')

const useMultiple = svgWithMultipleAttrs.children[0]

expect(useMultiple.getAttributeNS(XLINK_NS, 'href'))
  .to.equal('#icon-settings')

uuidV1

const uuidV1: (date?: Date, node?: string) => string;

Generates a UUID v1 (time-based) identifier.

date

The date to use for the timestamp portion (default: current date/time).

node

A hexadecimal string for the node portion (default: random). Must match /^[0-9a-f]*$/; it is trimmed to the last 12 characters and left-padded with zeros if shorter.

Returns

A UUID v1 string in the standard format xxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx.

Usage Examples

for (let i = 1; i <= 22136; ++i) {
  const uuid = uuidV1()

  if (i === 1) {
    expect(uuid.split('-')[3]).to.equal('8001')
  }

  if (i === 4095) {
    expect(uuid.split('-')[3]).to.equal('8fff')
  }

  if (i === 4096) {
    expect(uuid.split('-')[3]).to.equal('9000')
  }

  if (i === 9029) {
    expect(uuid.split('-')[3]).to.equal('a345')
  }

  if (i === 13398) {
    expect(uuid.split('-')[3]).to.equal('b456')
  }

  if (i === 16384) {
    expect(uuid.split('-')[3]).to.equal('8000')
  }

  if (i === 17767) {
    expect(uuid.split('-')[3]).to.equal('8567')
  }
}

expect(uuidV1(new Date(), '000123456789abc').split('-')[4])
  .to.equal('123456789abc')

expect(uuidV1(new Date(), '123456789').split('-')[4])
  .to.equal('000123456789')

expect(
  uuidV1(new Date(323325000000))
    .startsWith('c1399400-9a71-11bd'),
)
  .to.be.true

vivify

const vivify: (ref: unknown) => any;

A Proxy-based helper for auto-vivification of nested object structures.

Accessing, assigning, or deleting any nested property on the returned proxy automatically creates intermediate objects (or arrays for numeric-string keys matching ^(0|[1-9]\d*)$) as needed, allowing deep operations without explicit null checks.

Intermediates of the last level in a get-only property chain are NOT auto-created. For example, vivify(ref).one.two will create ref.one as {}, but will NOT create ref.one.two. Only when a deeper access, assignment, or deletion occurs (e.g. delete vivify(ref).one.two.three or vivify(ref).one.two.three = 4) will ref.one.two be materialized.

When traversal reaches a primitive value, no auto-creation happens; the primitive’s own property is returned instead (e.g. accessing .toString.name on a number yields 'toString' without modifying the underlying structure).

Deletion on a non-existing intermediate path will auto-create intermediates up to the parent of the deleted key (e.g. delete vivify(ref).one.two.three will create ref.one.two as {} if it does not exist).

ref

The root object to wrap.

Returns

A proxy that auto-creates nested objects/arrays on property access.

Usage Examples

const ref: any = {}

vivify(ref).one.two[3][4]

expect(ref).to.deep.equal(
  {
    one: {
      two: [undefined, undefined, undefined, []],
    },
  },
)

vivify(ref).one.two[3][4] = 5

expect(ref).to.deep.equal(
  {
    one: {
      two: [
        undefined,
        undefined,
        undefined,
        [undefined, undefined, undefined, undefined, 5],
      ],
    },
  },
)

vivify(ref).one.two[3].length = 1

expect(ref).to.deep.equal(
  {
    one: {
      two: [undefined, undefined, undefined, [undefined]],
    },
  },
)

vivify(ref).one.two[3] = 4

expect(ref).to.deep.equal(
  {
    one: {
      two: [undefined, undefined, undefined, 4],
    },
  },
)

expect(vivify(ref).one.two.length).to.equal(4)

expect(ref).to.deep.equal(
  {
    one: {
      two: [undefined, undefined, undefined, 4],
    },
  },
)

vivify(ref).one.two = 3

expect(ref).to.deep.equal({ one: { two: 3 } })

vivify(ref).one.two = undefined

expect(ref).to.deep.equal({ one: { two: undefined } })

delete vivify(ref).one.two

expect(ref).to.deep.equal({ one: {} })

expect(vivify(ref).one.toString instanceof Function)
  .to.be.true

expect(vivify(ref).one.toString.name).to.equal('toString')

expect(ref).to.deep.equal({ one: {} })

delete vivify(ref).one.two.three

expect(ref).to.deep.equal({ one: { two: {} } })

vivify(ref).one.two.three.four

expect(ref).to.deep.equal({ one: { two: { three: {} } } })

vivify(ref).one.two[3]

expect(ref).to.deep.equal({ one: { two: { three: {} } } })

vivify(ref).one.two.three.four = 5

expect(ref)
  .to.deep.equal({ one: { two: { three: { four: 5 } } } })

expect(vivify(ref).one.two.three.four.toString.name)
  .to.equal('toString')

expect(ref)
  .to.deep.equal({ one: { two: { three: { four: 5 } } } })

const u = undefined

vivify(u).one.two = 3

expect(u).to.be.undefined

const n = null

delete vivify(n).one.two.three

expect(n).to.be.null

License

The MIT License (MIT)

Copyright (c) 2016+ Jackens

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.