
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
@jackens/jc
Advanced tools
A collection of useful JavaScript helpers.
Helper that verifies deeply equality of two arguments of any type.
Usage example from unit tests:
import { deep_equal } from '../src/deep_equal.js'
import { it } from '../src/it.js'
it('should work', () => {
deep_equal(true, true).should.be.true
deep_equal(true, false).should.be.false
deep_equal(false, true).should.be.false
deep_equal(false, false).should.be.true
deep_equal(null, null).should.be.true
deep_equal(null, undefined).should.be.false
deep_equal(undefined, null).should.be.false
deep_equal(undefined, undefined).should.be.true
deep_equal(42, 42).should.be.true
deep_equal(42, '42').should.be.false
deep_equal('42', 42).should.be.false
deep_equal('42', '42').should.be.true
deep_equal([1, { a: 2, b: 3 }, 4], [1, { b: 3, a: 2 }, 4]).should.be.true
deep_equal([1, { a: 2, b: 3 }, 4], [1, { b: 3, a: '2' }, 4]).should.be.false
deep_equal([1, { a: 2, b: 3 }, 4], [1, { b: 3, a: 2 }, '4']).should.be.false
deep_equal(Object.create(null), {}).should.be.true
deep_equal(() => { }, () => { }).should.be.false
const keys = 'abcdefghilklmnopqrstuvwxyz0123456789_$'.split('')
const a = [{}, {}, {}]
const t = [a[0], a[1], a[2]]
for (let i = 0; i < t.length; ++i) {
for (let k = 0; k < 10000; ++k) {
t[i] = t[i][keys[k % keys.length]] = {}
}
t[i].deepest = !i
// console.log(JSON.stringify(a[i])) // Maximum call stack size exceeded
}
deep_equal(a[0], a[1]).should.be.false
deep_equal(a[0], a[2]).should.be.false
deep_equal(a[1], a[2]).should.be.true
})
Helper that verifies deeply equality of two arguments of any type. An iterative implementation that does not cause a stack overflow exception.
any
any
boolean
Helper for handling client-side (web browser) generated downloads.
Usage example from unit tests:
import { it } from '../src/it.js'
import { download } from '../src/download.js'
it('should work', () => {
download('Some content', 'name.txt', 'plain/text')
})
Helper for handling client-side (web browser) generated downloads.
BlobPart[]=
string=
string=
A set of helpers for working with objects and arrays.
Usage example from unit tests:
import { arr, get, obj, set } from '../src/elvis.js'
import { it } from '../src/it.js'
it('should create array of proper values', () => {
const actual = arr` ${'The answer'} to life the universe and everything:
${42}${true} `
const expected = [
'The answer', 'to', 'life', 'the', 'universe', 'and', 'everything:',
42, true
]
actual.should.be.deep.equal(expected)
})
it('should get existing non-nested property', () => {
const actual_1 = { a: 42 }
get(actual_1, 'a').should.be.equal(42)
})
it('should get existing nested property and get undefined for non existing nested property', () => {
const actual_2 = {
The: {
answer: {
to: {
life: {
the: {
universe: {
and: {
everything: 42
}
}
}
}
}
}
}
}
get(actual_2, ...arr`The answer to life the universe and everything`).should.be.equal(42)
expect(get(actual_2, ...arr`The answer to life the Universe and everything`)).to.be.undefined
})
it('should set not existing non-nested property', () => {
const actual_1 = {}
set(actual_1).a = 42
actual_1.should.be.deep.equal({ a: 42 })
})
it('shoud set not existing nested property', () => {
const actual_2 = {}
set(actual_2, ...arr`E l v i`).s = 42
actual_2.should.be.deep.equal({ E: { l: { v: { i: { s: 42 } } } } })
})
it('should create object of undefined values', () => {
const actual = obj` The answer to life the universe and everything:
${42} is greater than ${17} `
const expected = {
The: undefined,
answer: undefined,
to: undefined,
life: undefined,
the: undefined,
universe: undefined,
and: undefined,
'everything:': undefined,
42: undefined,
is: undefined,
greater: undefined,
than: undefined,
17: undefined
}
expect(actual).to.be.deep.equal(expected)
})
Array from tagged template literal.
TemplateStringsArray
any[]
any[]
Object from tagged template literal.
[TemplateStringsArray, ...any[]]
{
[key: string]: undefined;
}
Helper similar to ? operator (Elvis operator) for easy accessing nested object values.
object
string[]
object=
Helper similar to ? operator (Elvis operator) for easy assigning values to nested objects.
object
string[]
object=
Helper implementing typographic corrections appropriate for Polish typography.
Usage example from unit tests:
import { j } from '../src/j.js'
import { fix_typography } from '../src/fix_typography.js'
import { it } from '../src/it.js'
it('should work', () => {
const p = j({
t: 'p',
k: {
innerHTML: 'a b c d e f g h i j k l m n o p q r s t u v w x y z ' +
'https://example.com ' +
'<a href="https://example.com">https://example.com</a>'
}
}).e
fix_typography(p)
p.outerHTML.replace(/\u200B/g, '​').should.be.equal(
'<p>a b c d e f g h ' +
'<span class="nbsp">i </span>j k l m n ' +
'<span class="nbsp">o </span>p q r s t ' +
'<span class="nbsp">u </span>v ' +
'<span class="nbsp">w </span>x y ' +
'<span class="nbsp">z </span>' +
'https:/​/​example.​com ' +
'<a href="https://example.com">' +
'https:/​/​example.​com' +
'</a></p>'
)
})
Helper implementing typographic corrections appropriate for Polish typography. An iterative implementation that does not cause a stack overflow exception.
HTMLElement
A set of helpers for Full-Text Search.
Usage example from unit tests:
import { substitution_costs_default, fts_index, fts_rank, levenshtein_distance, substitution_costs_pl } from '../src/fts.js'
import { it } from '../src/it.js'
it('should work', () => {
const count_word_id = {}
const count_word = {}
const count_id = {}
const index = fts_index.bind(0, count_word_id, count_word, count_id)
const rank = fts_rank.bind(0, count_word_id, count_word, count_id)
index('one', 1)
index('one', 2)
index('two', 2)
index('two', 3)
rank('one').should.be.deep.equal({ 1: 0.5, 2: 0.25 })
rank('two').should.be.deep.equal({ 2: 0.25, 3: 0.5 })
})
it('should correctly calculate the Levenshtein distance', () => {
const levenshtein = levenshtein_distance.bind(null, 1, 1, substitution_costs_default)
levenshtein('kot', 'kat').should.be.equal(1)
levenshtein('koty', 'kat').should.be.equal(2)
levenshtein('levenshtein', 'lewensztejn').should.be.equal(3)
levenshtein('kitten', 'sitting').should.be.equal(3)
levenshtein('kat', 'kąt').should.be.equal(1)
const levenshtein_pl = levenshtein_distance.bind(null, 1, 1, substitution_costs_pl)
levenshtein_pl('kat', 'kąt').should.be.equal(0.3)
})
Helper that indexes the specified word within the specified id.
{
[word: string]: {
[id: string]: number;
};
}
{
[word: string]: number;
}
{
[id: string]: number;
}
string
string
number=
Helper that searches for the given word among indexed words.
Returns a map of non-zero relevance coefficients for registered identifiers.
{
[word: string]: {
[id: string]: number;
};
}
{
[word: string]: number;
}
{
[id: string]: number;
}
string
{
[id: string]: number;
}=
{
[id: string]: number;
}
Helper that creates count_word and count_id maps based on the count_word_id map.
{
[word: string]: {
[id: string]: number;
};
}
[{
[word: string]: number;
}, {
[id: string]: number;
}]
The substitution cost function used by levenshtein_distance.
string
string
number
Default substitution costs function to use with levenshtein_distance.
SUBSTITUTION_COST
Substitution costs function for the Polish language (to use with levenshtein_distance).
SUBSTITUTION_COST
Helper for calculating Levenshtein distances.
number
number
SUBSTITUTION_COST
string
string
number
Replacement for the in operator (not to be confused with the for-in loop) that works properly.
Usage example from unit tests:
import { it } from '../src/it.js'
import { is_in } from '../src/is_in.js'
it('should work', () => {
const ob = { key: 'K', null: 'N' }
expect('key' in ob).to.be.true
is_in('key', ob).should.be.true
expect('null' in ob).to.be.true
is_in('null', ob).should.be.true
expect(null in ob).to.be.true
is_in(null, ob).should.be.false
expect('toString' in ob).to.be.true
is_in('toString', ob).should.be.false
is_in('key', null).should.be.false
})
Replacement for the in operator (not to be confused with the for-in loop) that works properly.
any
any
boolean
A simple helper for various types of tests (especially unit tests).
A simple helper for various types of tests (especially unit tests).
string
function
Prints a summary of the tests.
number
Lightweight helper for creating and modifying DOM elements.
Usage example from unit tests:
import { it } from '../src/it.js'
import { j, j_style, j_svg, j_svg_use, j_symbol, toe } from '../src/j.js'
it('should create <b><i> with class attribute and textContent', () => {
j({
t: 'b',
i: [{
t: 'i', k: { className: 'some class', textContent: 'text' }
}]
}).e.outerHTML.should.be.equal('<b><i class="some class">text</i></b>')
})
const b = j({ t: 'b' })
it('should create empty <b>', () => {
b.e.outerHTML.should.be.equal('<b></b>')
})
const i = j({
t: 'i', i: [{ e: 'text' }], p: b.e
})
it('should create <i> with previous <b> as a child', () => {
i.e.outerHTML.should.be.equal('<i>text</i>')
b.e.outerHTML.should.be.equal('<b><i>text</i></b>')
})
j({
e: i.e, k: { className: 'some class' }
})
it('should add some class to previous <i> and previous <b>', () => {
i.e.outerHTML.should.be.equal('<i class="some class">text</i>')
b.e.outerHTML.should.be.equal('<b><i class="some class">text</i></b>')
})
it('should set textContent by child node', () => {
j({
t: 'span', k: { className: 'some class' }, i: [{ e: 0 }]
}).e.outerHTML.should.be.equal('<span class="some class">0</span>')
})
it('should set textContent by textContent property', () => {
j({
t: 'span', k: { className: 'some class', textContent: 'one' }
}).e.outerHTML.should.be.equal('<span class="some class">one</span>')
})
it('should set style by style properties', () => {
j({
t: 'div',
k: {
style: { margin: 0 }
}
}).e.outerHTML.should.be.equal('<div style="margin: 0px;"></div>')
})
it('should create <div> with child nodes', () => {
j({
t: 'div',
k: { className: 'some class' },
i: [{
t: 'b', i: [{ e: 'bold 1' }]
}, {
t: 'b', i: [{ e: 'bold 2' }]
}, {
t: 'i', i: [{ e: 'italic' }]
}]
}).e.outerHTML.should.be.equal(
'<div class="some class">' +
'<b>bold 1</b><b>bold 2</b><i>italic</i>' +
'</div>')
})
const input_1 = j({
t: 'input', k: { value: 42 }
})
const input_2 = j({
t: 'input', a: { value: 42 }
})
it('should set <input> value set by value property', () => {
input_1.e.value.should.be.equal('42')
})
it('should set <input> value set by value attribute', () => {
input_2.e.value.should.be.equal('42')
})
it('should not expose <input> value attribute set by value property', () => {
input_1.e.outerHTML.should.be.equal('<input>')
})
it('should expose <input> value attribute set by value attribute', () => {
input_2.e.outerHTML.should.be.equal('<input value="42">')
})
it('should wrap the argument to an object with a single property ‘e’', () => {
toe(42).should.be.deep.equal({ e: 42 })
})
it('should handle boolean attributes in a special way', () => {
j({
t: 'input', a: { type: 'checkbox', checked: true }
}).e.outerHTML.should.be.equal('<input type="checkbox" checked="">')
j({
t: 'input', a: { type: 'checkbox', checked: false }
}).e.outerHTML.should.be.equal('<input type="checkbox">')
j({
t: 'input', a: { type: 'checkbox', 'xhtml:checked': true }
}).e.outerHTML.should.be.equal('<input type="checkbox" checked="">')
j({
t: 'input', a: { type: 'checkbox', 'xhtml:checked': false }
}).e.outerHTML.should.be.equal('<input type="checkbox">')
})
it('should assign the property by reference if assignment by subkeys is not possible', () => {
j({
t: 'div', k: { key: { key_2: 42 } }
}).e.key.should.be.deep.equal({ key_2: 42 })
})
it('should work', () => {
j_symbol({}).e.outerHTML.should.be.equal('<symbol></symbol>')
j_symbol({ t: 'non-symbol' }).e.outerHTML.should.be.equal('<symbol></symbol>')
j_symbol({ a: { id: 'id' } }).e.outerHTML.should.be.equal('<symbol id="id"></symbol>')
})
it('should work', () => {
j_svg([{
a: { viewBox: '0 1 2 3', id: 'id' },
i: [{ t: 'some-tag' }]
}]).e.outerHTML.should.be.equal(
'<svg style="display: none;">' +
'<symbol viewBox="0 1 2 3" id="id"><some-tag></some-tag></symbol>' +
'</svg>')
})
it('should handle id', () => {
j(j_svg_use('id')).e.outerHTML.replace('xlink:', '').should.be.equal(
'<svg><use href="#id"></use></svg>')
})
it('should handle extra attributes', () => {
j({
...j_svg_use('id'),
a: { fill: '#000', stroke: '#000', width: 42, height: 42 }
}).e.outerHTML.replace('xlink:', '').should.be.equal(
'<svg fill="#000" stroke="#000" width="42" height="42">' +
'<use href="#id"></use>' +
'</svg>')
})
it('should work', () => {
const js_style = {
a: { b$$1: 1, b$$2: 2 }
}
j_style(js_style).e.outerHTML.should.be.equal(
'<style>a{b:1;b:2}</style>')
j_style(js_style, '$$$').e.outerHTML.should.be.equal(
'<style>a{b$$1:1;b$$2:2}</style>')
})
The j helper configuration.
{
[attribute: string]: any;
}?
attributes of the created or modified element set by setAttribute or setAttributeNS
(Element | Text | string | number)?
modified element
J_CONFIG[]?
an array of subelements (items) of the created or modified element
{
[key: string]: any;
}?
properties (keys) to set in the created or modified element
string?
namespace for createElementNS, setAttributeNS and removeAttributeNS methods
Element?
reference to the parent element for the created or modified element
string?
tag of the created element
Result type of the j helper.
T
Lightweight helper for creating and modifying DOM elements.
J_CONFIG
E<Element | HTMLElement | Text>
T
E<T>
Helper for creating <symbol> elements.
J_CONFIG
E<SVGSymbolElement>
Helper for creating <svg> container elements.
Array<J_CONFIG>
E<SVGSVGElement>
Helper for creating <svg><use> elements.
string
J_CONFIG
Helper for creating <style> elements.
JSS
string=
E<HTMLStyleElement>
Jackens’ Components.
Jackens’ Components configuration format (JCMP_CONFIG) is based on three main keys:
w (wrapper): J_CONFIG format configuration of the component wrapper (HTMLDivElement element)c (control): J_CONFIG format configuration of the component controll (label): J_CONFIG format configuration of the component label (HTMLLabelElement element; applies to input controls of type checkbox, radio and file)All other keys are just an alternative, more convenient form for configuration using the main keys.
The sample file selection button component shown below

has the following HTML representation:
<body>
<div class="jcmp" label="Label">
<input type="file" id="jcmp-1" />
<div>
<label for="jcmp-1">Text</label>
</div>
</div>
<script type="module">
import { j, j_style } from '../../src/j.js'
import { jcmp_jss } from '../../src/jcmp.js'
window.onload = () => j({
e: document.body,
i: [j_style(jcmp_jss())]
})
</script>
</body>
The file selection button component shown above can be generated with the following code:
<script type="module">
import { j, j_style } from '../../src/j.js'
import { jcmp, jcmp_jss } from '../../src/jcmp.js'
window.onload = () => j({
e: document.body,
i: [
j_style(jcmp_jss()),
jcmp({ type: 'file', label: 'Label', text: 'Text' })
]
})
</script>
The JCMP_CONFIG format has the following default values:
{ […], t: 'input', class: 'jcmp', […] }
The icon and text keys are handled in a special way: they allow you to conveniently specify the icon and text of the component you are defining.
Jackens’ Components layout system contains only two types of classes:
.w-«w»-«sw»: width of «w» slots when the screen is wide enough for «sw» slots..h-«h»-«sw»: height of «h» slots when the screen is wide enough for «sw» slots.The minimum slot width is 200 pixels.
Example. Components defined as follows:
<script type="module">
import { j, j_style } from '../../src/j.js'
import { jcmp, jcmp_jss } from '../../src/jcmp.js'
window.onload = () => j({
e: document.body,
i: [
j_style(jcmp_jss()),
jcmp({
label: 'Component #1',
class: 'jcmp w-1-3 w-1-2',
text: 'jcmp w-1-3 w-1-2'
}), jcmp({
label: 'Component #2',
class: 'jcmp w-1-3 w-1-2',
text: 'jcmp w-1-3 w-1-2'
}), jcmp({
label: 'Component #3',
class: 'jcmp w-1-3',
text: 'jcmp w-1-3'
})
]
})
</script>
on a screen at least 600 pixels wide, will be arranged on a single line:

on a screen less than 600 pixels wide, but not less than 400 pixels wide, will be arranged in two lines:

while on a screen less than 400 pixels wide, they will be arranged in three rows:

Jackens’ Components configuration.
J_CONFIG?
wrapper configuration
J_CONFIG?
control configuration
J_CONFIG?
label configuration
string?
w.a.class configuration
string?
w.a.label configuration
HTMLElement?
w.p configuration
any?
c.k.onchange configuration
any?
c.k.onclick configuration
any?
c.k.oninput configuration
any?
c.k.onkeyup configuration
{
[key: string]: any;
}?
c.k.style configuration
string?
c.t configuration
string?
icon
string?
text
Convenient converter from JCMP_CONFIG format to J_CONFIG format.
import { it } from '../src/it.js'
import { j_svg_use } from '../src/j.js'
import { jcmp, jcmp_jss } from '../src/jcmp.js'
const svg_use_config = {
a: { fill: '#fff', stroke: '#fff', width: 17, height: 17 }
}
const button_1 = jcmp({
t: 'button',
w: {
a: { class: 'jcmp' }
},
c: {
a: { 'aria-label': 'button' },
i: [{
...j_svg_use('icon-id'), ...svg_use_config
}, {
t: 'div'
}, {
e: 'Button'
}],
k: {
style: { marginLeft: 42, marginRight: 17 },
onclick: console.log // eslint-disable-line no-console
}
}
})
const button_2 = jcmp({
t: 'button',
style: { marginLeft: 42, marginRight: 17 },
onclick: console.log, // eslint-disable-line no-console
text: 'Button',
icon: 'icon-id',
'aria-label': 'button'
})
it('should handle keys ‘style’, ‘onclick’ and ‘aria-label’', () => {
button_2.should.be.deep.equal(button_1)
})
const file_1 = jcmp({
t: 'input',
type: 'file',
w: {
a: { class: 'jcmp' }
},
l: {
i: [{ e: 'Choose file…' }]
}
})
const file_2 = jcmp({
t: 'input', type: 'file', text: 'Choose file…'
})
it('should add class ‘jcmp’ automatically and handle key ‘text’', () => {
file_2.i[0].a.id = file_2.i[1].i[0].a.for = 'jcmp-1'
file_2.should.be.deep.equal(file_1)
})
const css = jcmp_jss()
it('should generate proper CSS', () => {
css.should.be.string
})
JCMP_CONFIG
J_CONFIG
Jackens’ Components CSS rules in JSS format.
{
font_family?: string;
focus_color?: string;
main_color?: string;
}
JSS
JSON.parse with “JavaScript turned on”.
Usage example from unit tests:
import { it } from '../src/it.js'
import { js_on_parse } from '../src/js_on_parse.js'
const handlers = {
join: (...params) => params.join(' '),
outer: text => `Hello ${text}!`,
inner: text => text.charAt(0).toUpperCase() + text.slice(1).toLowerCase(),
question: text => ({ d: 'Yes!', t: 42 }[text[0]])
}
it('should use ‘join’ handler', () => {
js_on_parse(`{
"join": ["Hello", "World!"]
}`, handlers).should.be.deep.equal('Hello World!')
})
it('should ‘join’ and ‘to_much’ handlers', () => {
js_on_parse(`{
"join": ["Hello", "World!"], "to_much": "whatever"
}`, handlers).should.be.deep.equal({
join: ['Hello', 'World!'], to_much: 'whatever'
})
})
it('should use ‘inner’ and ‘outer’ handlers', () => {
js_on_parse(`{
"outer":{ "inner": "wORld" }
}`, handlers).should.be.deep.equal('Hello World!')
})
it('should use ‘question’ handler', () => {
js_on_parse(`[{
"question": "does it really works?!?"
}, {
"question": "the answer to life the universe and everything"
}, {
"Question": null
}]`, handlers).should.be.deep.equal(['Yes!', 42, { Question: null }])
})
it('should process nested objects', () => {
js_on_parse('{"H":{"e":{"l":{"l":{"o":["World!"]}}}}}', handlers)
.should.be.deep.equal({ H: { e: { l: { l: { o: ['World!'] } } } } })
})
Objects having exactly one «handlerName» property present in the handlers map, i.e. objects of form:
{ "«handlerName»": «param» }
and
{ "«handlerName»": [«params»] }
are replaced by the result of call
handlers['«handlerName»'](«param»)
and
handlers['«handlerName»'](...«params»)
Remark. To pass to handlers['«handlerName»'] a single argument that is an array, use the following form:
{ "«handlerName»": [[«elements»]] }
which will force a call
handlers['«handlerName»']([«elements»])
JSON.parse with “JavaScript turned on”.
string
{
[handler_name: string]: function;
}
any
CSS-in-JS helper based on the JSS format.
The JSS format provides a hierarchical description of CSS rules.
src$$1 → src, -face$$1 → -face).- character preceding them (e.g. fontFamily → font-family).{div:{margin:1,'.a,.b,.c':{margin:2}}} → div{margin:1}div.a,div.b,div.c{margin:2}).@ are not concatenated with sub-object keys.Usage example from unit tests:
import { it } from '../src/it.js'
import { jss } from '../src/jss.js'
it('should handle nested definitions (level 1)', () => {
const actual_1 = {
a: {
color: 'red',
margin: 1,
'.c': {
margin: 2,
padding: 2
},
padding: 1
}
}
const expected_1 =
'a{color:red;margin:1}' +
'a.c{margin:2;padding:2}' +
'a{padding:1}'
jss(actual_1).should.be.equal(expected_1)
})
it('should handle nested definitions (level 2)', () => {
const actual_2 = {
a: {
'.b': {
color: 'red',
margin: 1,
'.c': {
margin: 2,
padding: 2
},
padding: 1
}
}
}
const expected_2 =
'a.b{color:red;margin:1}' +
'a.b.c{margin:2;padding:2}' +
'a.b{padding:1}'
jss(actual_2).should.be.equal(expected_2)
})
it('should handle ‘@’ prefixes and ‘$$suffix’ suffixes', () => {
const actual_3 = {
'@font-face$$1': {
fontFamily: 'Jackens',
src$$1: 'url(fonts/jackens.otf)',
src$$2: "url(fonts/jackens.otf) format('opentype')," +
"url(fonts/jackens.svg) format('svg')",
fontWeight: 'normal',
fontStyle: 'normal'
},
'@font-face$$2': {
fontFamily: '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': { backgroundColor: 'black' },
'.c2': { backgroundColor: 'rgb(0,0,0)' }
},
'@media(min-width:200px)': {
div: { margin: 0, padding: 0 },
span: { color: '#000' }
}
}
const expected_3 = '@font-face{font-family:Jackens;src:url(fonts/jackens.otf);' +
"src:url(fonts/jackens.otf) format('opentype')," +
"url(fonts/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}}'
jss(actual_3).should.be.equal(expected_3)
})
it('should handle comma separation (level 2)', () => {
const actual_4 = {
a: {
'.b,.c': {
margin: 1,
'.d': {
margin: 2
}
}
}
}
const expected_4 = 'a.b,a.c{margin:1}a.b.d,a.c.d{margin:2}'
jss(actual_4).should.be.equal(expected_4)
})
it('should handle comma separation (level 1)', () => {
const actual_5 = {
'.b,.c': {
margin: 1,
'.d': {
margin: 2
}
}
}
const expected_5 = '.b,.c{margin:1}.b.d,.c.d{margin:2}'
jss(actual_5).should.be.equal(expected_5)
})
it('should handle multiple comma separations', () => {
const actual_6 = {
'.a,.b': {
margin: 1,
'.c,.d': {
margin: 2
}
}
}
const expected_6 = '.a,.b{margin:1}' +
'.a.c,.a.d,.b.c,.b.d{margin:2}'
jss(actual_6).should.be.equal(expected_6)
})
{
[rule_or_attribute: string]: string | number | JSS;
}
CSS-in-JS helper based on the JSS format.
An iterative implementation that does not cause a stack overflow exception.
JSS
string=
string
Converter from JSDoc to Markdown.
Usage example from unit tests (used to generate this documentation):
import { js_on_parse } from '../src/js_on_parse.js'
import { mdoc, read_file, write_file } from '../src/mdoc.js'
const config = {
write_file: {
lines: [
{ read_file: 'header.md' },
'\n# Modules\n',
{ mdoc: {} },
'\n# License\n',
{ read_file: 'LICENSE' }
],
path: 'readme.md'
}
}
js_on_parse(JSON.stringify(config), { mdoc, read_file, write_file })
Handler that reads the contents of the specified file.
string
string
Converter from JSDoc to Markdown.
{
src?: string[];
extra_ids?: boolean;
}
string
Helper that writes an array of lines to the specified file.
{
lines: string[];
path: string;
}
string
Helper for converting integers to map-friendly string identifiers.
Usage example from unit tests:
import { it } from '../src/it.js'
import { num_to_key } from '../src/num_to_key.js'
const ALPHA = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$'
const _1_TO_9 = '123456789'
const _0_TO_9 = `0${_1_TO_9}`
const ALPHA_NUM = `${_0_TO_9}${ALPHA}`
const KEYS = []
for (let a = 0; a < ALPHA_NUM.length; ++a) {
KEYS.push(ALPHA_NUM[a])
}
for (let a = 0; a < _1_TO_9.length; ++a) {
for (let b = 0; b < _0_TO_9.length; ++b) {
KEYS.push(`${_1_TO_9[a]}${_0_TO_9[b]}`)
}
}
for (let a = 0; a < ALPHA.length; ++a) {
for (let b = 0; b < ALPHA_NUM.length; ++b) {
KEYS.push(`${ALPHA[a]}${ALPHA_NUM[b]}`)
}
}
for (let a = 0; a < _1_TO_9.length; ++a) {
for (let b = 0; b < _0_TO_9.length; ++b) {
for (let c = 0; c < _0_TO_9.length; ++c) {
KEYS.push(`${_1_TO_9[a]}${_0_TO_9[b]}${_0_TO_9[c]}`)
}
}
}
for (let a = 0; a < ALPHA.length; ++a) {
for (let b = 0; b < ALPHA_NUM.length; ++b) {
for (let c = 0; c < ALPHA_NUM.length; ++c) {
KEYS.push(`${ALPHA[a]}${ALPHA_NUM[b]}${ALPHA_NUM[c]}`)
}
}
}
it('should work', () => {
for (let num = 0; num < KEYS.length; ++num) {
num_to_key(num).should.be.equal(KEYS[num])
}
})
Helper for converting integers to map-friendly string identifiers.
number
string
Helper for choosing the correct singular and plural.
Usage example from unit tests:
import { it } from '../src/it.js'
import { pl_ural } from '../src/pl_ural.js'
it('should handle 0', () => {
pl_ural(0, 'car', 'cars', 'cars').should.be.equal('0 cars')
pl_ural(0, 'auto', 'auta', 'aut').should.be.equal('0 aut')
})
it('should handle 1', () => {
pl_ural(1, 'car', 'cars', 'cars').should.be.equal('1 car')
pl_ural(1, 'auto', 'auta', 'aut').should.be.equal('1 auto')
})
it('should handle 5', () => {
pl_ural(5, 'car', 'cars', 'cars').should.be.equal('5 cars')
pl_ural(5, 'auto', 'auta', 'aut').should.be.equal('5 aut')
})
it('should handle 2', () => {
pl_ural(42, 'car', 'cars', 'cars').should.be.equal('42 cars')
pl_ural(42, 'auto', 'auta', 'aut').should.be.equal('42 auta')
})
Helper for choosing the correct singular and plural.
number
string
string
string
string=
string=
string
Animated gear preloader.
Animated gear preloader.
E<SVGSVGElement>
Animated gear preloader CSS rules in JSS format.
JSS
Helper to scan files in the specified directories.
Unit tests:
import { it } from '../src/it.js'
import { scan_dirs } from '../src/scan_dirs.js'
it('should work', async () => {
const src = scan_dirs('src')
const test = scan_dirs('test')
const src_and_test = scan_dirs('src', 'test')
src.length.should.be.greaterThan(20)
test.length.should.be.greaterThan(30)
src_and_test.length.should.be.equal(src.length + test.length)
})
Helper to scan files in the specified directories.
...string
string[]
A set of helpers for creating safe SQL queries.
Usage example from unit tests:
import { it } from '../src/it.js'
import { mssql_name, mysql_name, sql, sql_name } from '../src/sql.js'
it('should work', () => {
const actual = sql`
SELECT *
FROM ${mysql_name('table`name')}
WHERE
${sql_name('column"name')} = ${42} OR
${mssql_name('[column][name]')} = ${"'"} OR
column_name = ${true} OR
column_name = ${false} OR
column_name = ${new Date('1980-03-31T04:30:00.000Z')} OR
column_name IN (${[42, "'", true, false, new Date('1980-03-31T04:30:00.000Z')]})`
const expected = `
SELECT *
FROM \`table\`\`name\`
WHERE
"column""name" = 42 OR
[[column]][name]]] = '''' OR
column_name = b'1' OR
column_name = b'0' OR
column_name = '1980-03-31 04:30:00' OR
column_name IN (42,'''',b'1',b'0','1980-03-31 04:30:00')`
actual.should.be.equal(expected)
})
{
[Symbol.toStringTag]: string;
toString: () => string;
}
Helper for escaping SQL column, table and schema names.
string
SQL_NAME
Helper for escaping MySQL/MariaDB column, table and schema names.
string
SQL_NAME
Helper for escaping MS SQL column, table and schema names.
string
SQL_NAME
Helper for escaping values.
any
string
Tagged Template Literal helper for creating secure SQL queries.
TemplateStringsArray
any[]
string
Methods that implement value escape for particular types.
{
[type: string]: (value: any) => string;
}
Helper for converting streams to buffers.
Usage example from unit tests:
import { createReadStream } from 'fs'
import { it } from '../src/it.js'
import { stream_to_buffer } from '../src/stream_to_buffer.js'
it('should work', async () => {
const stream = createReadStream('src/stream_to_buffer.js')
const buffer = await stream_to_buffer(stream)
buffer.toString('utf8').includes('export const stream_to_buffer =')
.should.be.true
})
Helper for converting streams to buffers.
Stream
Promise<Buffer>
Language translations helper.
Usage example from unit tests:
import { it } from '../src/it.js'
import { translate } from '../src/translate.js'
const locales = {
pl: {
Password: 'Hasło',
button: { Login: 'Zaloguj' }
}
}
const _ = translate.bind(0, locales, 'pl')
it('should handle defined texts', () => {
_('Login').should.be.equal('Login')
_('Password').should.be.equal('Hasło')
})
it('should handle undefined text', () => {
_('Undefined text').should.be.equal('Undefined text')
})
it('should handle defined version', () => {
_('Login', 'button').should.be.equal('Zaloguj')
})
it('should handle undefined version', () => {
_('Password', 'undefined_version').should.be.equal('Hasło')
_('Undefined text', 'undefined_version').should.be.equal('Undefined text')
})
it('should have empty prototype', () => {
_('toString').should.be.equal('toString')
_('toString', 'undefined_version').should.be.equal('toString')
})
Language translations helper.
{
[lang: string]: {
[text_or_version: string]: string | {
[text: string]: string;
};
};
}
string
string
string=
string
{
[lang: string]: {
[text_or_version: string]: string | {
[text: string]: string;
};
};
}
string
A collection of type testing helpers.
Usage example from unit tests:
import { it } from '../src/it.js'
import {
is_Array,
is_AsyncFunction,
is_Boolean,
is_Date,
is_Element,
is_Function,
is_GeneratorFunction,
is_HTMLButtonElement,
is_HTMLInputElement,
is_HTMLTextAreaElement,
is_Number,
is_Object,
is_Promise,
is_RegExp,
is_String,
is_Text,
type_of
} from '../src/type_of.js'
it('should work', () => {
expect(typeof []).to.be.equal('object')
type_of([]).should.be.equal('Array')
is_Array([]).should.be.true
expect(typeof (async () => { })).to.be.equal('function')
type_of(async () => { }).should.be.equal('AsyncFunction')
is_AsyncFunction(async () => { }).should.be.true
expect(typeof true).to.be.equal('boolean')
type_of(true).should.be.equal('Boolean')
is_Boolean(true).should.be.true
expect(typeof new Date()).to.be.equal('object')
type_of(new Date()).should.be.equal('Date')
is_Date(new Date()).should.be.true
expect(typeof document.createElement('DIV')).to.be.equal('object')
type_of(document.createElement('DIV')).should.be.equal('HTMLDivElement')
is_Element(document.createElement('DIV')).should.be.true
expect(typeof function * () {}).to.be.equal('function')
type_of(function * () {}).should.be.equal('GeneratorFunction')
is_GeneratorFunction(function * () {}).should.be.true
expect(typeof type_of).to.be.equal('function')
type_of(type_of).should.be.equal('Function')
is_Function(type_of).should.be.true
is_HTMLButtonElement(document.createElement('BUTTON')).should.be.true
is_HTMLInputElement(document.createElement('INPUT')).should.be.true
is_HTMLTextAreaElement(document.createElement('TEXTAREA')).should.be.true
expect(typeof 42).to.be.equal('number')
type_of(42).should.be.equal('Number')
is_Number(42).should.be.true
expect(typeof NaN).to.be.equal('number')
type_of(NaN).should.be.equal('Number')
is_Number(NaN).should.be.true
expect(typeof Infinity).to.be.equal('number')
type_of(Infinity).should.be.equal('Number')
is_Number(Infinity).should.be.true
expect(typeof {}).to.be.equal('object')
type_of({}).should.be.equal('Object')
is_Object({}).should.be.true
expect(typeof Promise.resolve()).to.be.equal('object')
type_of(Promise.resolve()).should.be.equal('Promise')
is_Promise(Promise.resolve()).should.be.true
expect(typeof /^(Reg)(Exp)$/).to.be.equal('object')
type_of(/^(Reg)(Exp)$/).should.be.equal('RegExp')
is_RegExp(/^(Reg)(Exp)$/).should.be.true
expect(typeof 'Jackens').to.be.equal('string')
type_of('Jackens').should.be.equal('String')
is_String('Jackens').should.be.true
expect(typeof String('Jackens')).to.be.equal('string')
type_of(String('Jackens')).should.be.equal('String')
is_String(String('Jackens')).should.be.true
expect(typeof new String('Jackens')).to.be.equal('object') // eslint-disable-line no-new-wrappers
type_of(new String('Jackens')).should.be.equal('String') // eslint-disable-line no-new-wrappers
is_String(new String('Jackens')).should.be.true // eslint-disable-line no-new-wrappers
is_Text(document.createTextNode('')).should.be.true
})
Replacement for the typeof operator that works properly.
any
string
Helper that checks if the arg is of type Array.
any
arg is Array
Helper that checks if the arg is of type AsyncFunction.
any
boolean
Helper that checks if the arg is of type Boolean.
any
arg is Boolean
Helper that checks if the arg is of type Date.
any
arg is Date
Helper that checks if the arg is of type Element.
any
arg is Element
Helper that checks if the arg is of type Function.
any
arg is Function
Helper that checks if the arg is of type GeneratorFunction.
any
arg is GeneratorFunction
Helper that checks if the arg is of type HTMLButtonElement.
any
arg is HTMLButtonElement
Helper that checks if the arg is of type HTMLInputElement.
any
arg is HTMLInputElement
Helper that checks if the arg is of type HTMLTextAreaElement.
any
arg is HTMLTextAreaElement
Helper that checks if the arg is of type Number.
any
arg is Number
Helper that checks if the arg is of type Object.
any
arg is Object
Helper that checks if the arg is of type Promise.
any
arg is Promise
Helper that checks if the arg is of type RegExp.
any
arg is RegExp
Helper that checks if the arg is of type String.
any
arg is String
Helper that checks if the arg is of type Text.
any
arg is Text
A collection of UUID v1 helpers.
Usage example from unit tests:
import { it } from '../src/it.js'
import { uuid_v1, uuid_v1_decode } from '../src/uuid_v1.js'
it('should contain a global counter', () => {
for (let i = 0; i < 4200; ++i) {
const counter = uuid_v1().split('-')[3]
if (i === 0) {
counter.should.be.equal('8001')
} else if (i === 4094) {
counter.should.be.equal('8fff')
} else if (i === 4095) {
counter.should.be.equal('8000')
} else if (i === 4096) {
counter.should.be.equal('8001')
}
}
})
it('should match regexp pattern', () => {
uuid_v1().should.match(
/^[\da-f]{8}-[\da-f]{4}-1[\da-f]{3}-8[\da-f]{3}-[\da-f]{12}$/)
})
it('should support the specified date and value', () => {
const uuid_1 = uuid_v1(new Date(323325e6), 205163983024656)
uuid_1.startsWith('c1399400-9a71-11bd').should.be.true
uuid_1.endsWith('-ba9876543210').should.be.true
const uuid_2 = uuid_v1(new Date(323325e6), 486638959735312)
uuid_2.startsWith('c1399400-9a71-11bd').should.be.true
uuid_2.endsWith('-ba9876543210').should.be.true
})
it('should decode date', () => {
const date_1 = new Date()
const uuid = uuid_v1(date_1)
const date_2 = uuid_v1_decode(uuid)
expect(+date_2).to.be.equal(+date_1)
})
UUID v1 identifier (containing creation timestamp) generator.
Date=
number=
string
Date extractor from UUID v1 identifier.
string
Date
Generic JSON RPC 2.0 WebSocket Client.
Usage examples:
<script type="module">
import { wsc } from '../../src/wsc.js'
window.onload = async () => {
const fs = await wsc('ws://localhost:12345/')
const list = await fs('list', { path: 'src' })
const file = await fs('read', { path: 'src/wsc.js' })
console.log(list)
console.log(file)
}
</script>
<script type="module">
import { wsc } from '../../src/wsc.js'
window.onload = async () => {
const mariadb = await wsc('ws://localhost:13306/')
const status = await mariadb('connect', {
config: { host: 'localhost', user: 'root', password: 'qwerty' }
})
const rows = await mariadb('query', { query: 'SELECT CURRENT_TIMESTAMP' })
console.log(status)
console.log(rows)
}
</script>
{
[id: string]: [function, function];
}
string
{
[key: string]: any;
}
Promise<any>
Generic JSON RPC 2.0 WebSocket Client.
string
WSC_HANDLERS=
Promise<WSC_SEND>
Generic JSON RPC 2.0 WebSocket Server.
{
clients: WebSocket[];
client: WebSocket;
params: {
[param_name: string]: any;
};
}
Promise<any>
Generic JSON RPC 2.0 WebSocket Server.
{
[method_name: string]: WSS_METHOD;
}
number
File System JSON RPC 2.0 WebSocket Server.
Usage example:
import { wss_fs } from '../../src/wss_fs.js'
wss_fs(12345)
File System JSON RPC 2.0 WebSocket Server.
(port: number) => void
MariaDB JSON RPC 2.0 WebSocket Server.
Usage example:
import { wss_mariadb } from '../../src/wss_mariadb.js'
wss_mariadb(13306)
MariaDB JSON RPC 2.0 WebSocket Server.
(port: number) => void
MIT License
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 A 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.
FAQs
Jackens’ Collection of useful JavaScript helpers.
The npm package @jackens/jc receives a total of 0 weekly downloads. As such, @jackens/jc popularity was classified as not popular.
We found that @jackens/jc demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.