npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hitext

v1.0.0-beta.1

Published

Text decoration done right

Downloads

291

Readme

HiText

NPM version Build Status Coverage Status

HiText is a basis for a text (source code) decoration. The main goal is to provide a universal way to combine libraries decorating text and an output in the required format (HTML, TTY etc). The only prerequsites you need are a source text and set of ranges with some options, the rest will be done by HiText.

Why?

Just imagine you want to output in HTML a JavaScript code with syntax highlighting and to spotlight some fragments of it. You can use a library for syntax highlighting, that's not a problem. For fragment spotlighting you can get substrings and wrap them into HTML tags. Both operations are not so hard, but the problem is to combine results of them. Each operation adds HTML tags to a result, so another operation will not perform as expected because of HTML tags.

The solution is to change such operations to produce a set of ranges instead of markup. Once ranges is generated, HiText can merge them by universal rules and get a stream of segments. As a final step, segment stream is used to generate open and close tags when needed.

The approach allows to combine any number of decorators (which became range generators). Moreover, using a source and a range set, it's possible to output a result in any format beside HTML. An output format is defined by a printer.

Features

  • Universal way to combine a number of decorators (generators)
  • Much easier to make a generator
  • Parsers with formatting losses can be used. No AST mutations required to decorate an input
  • Flexible setup for an output. Build-in printers: HTML, TTY (terminal)

Example

const hitext = require('hitext');
const prism = require('hitext-prism');
const spotlightRanges = [[6, 11], [19, 24]];
const spotlightPrinter = {
    html: {
        open() { return '<span class="spotlight">'; },
        close() { return '</span>'; }
    }
}
const lineNumber = {
    ranges: hitext.gen.lines,
    printer: {
        html: {
            open({ line }) { return line + ' | ' }
        }
    }
};

// 1. Create pipeline
const highlightJsAndSpotlight = hitext([
    prism('js'),
    [spotlightRanges, spotlightPrinter],
    lineNumber
], 'html');
// or
const highlightJsAndSpotlight = hitext([prism('js')], 'html')
    .use(spotlightRanges, spotlightPrinter)
    .use(lineNumber);
// or
const highlightJsAndSpotlight = hitext
    .use(prism('js'))
    .use({
        ranges: spotlightRanges,
        printer: spotlightPrinter
    })
    .use(lineNumber)
    .printer('html');

// 2. Apply to a text
console.log(highlightJsAndSpotlight('const a = 1;\nconst b = 2;'));

Output:

1 | <span class="token keyword">const</span> <span class="spotlight">a <span class="token operator">=</span> <span class="token number">1</span></span><span class="token punctuation">;</span>
2 | <span class="token keyword">const</span> <span class="spotlight">b <span class="token operator">=</span> <span class="token number">2</span></span><span class="token punctuation">;</span>

Build-in generators

lines

const hitext = require('hitext');

console.log(
    hitext()
        .use(hitext.gen.lines, {
            html: {
                open: ({ line }) => `<span title="line #${line}">`,
                close: () => '</span>'
            }
        })
        .print('foo\nbar', 'html')
);
// '<span title="line #1">foo\n</span><span title="line #2">foo</span>'

lineContents

const hitext = require('hitext');

console.log(
    hitext()
        .use(hitext.gen.lineContents, {
            html: {
                open: ({ line }) => `<span title="line #${line}">`,
                close: () => '</span>'
            }
        })
        .print('foo\nbar', 'html')
);
// '<span title="line #1">foo</span>\n<span title="line #2">foo</span>'

newlines

const hitext = require('hitext');

console.log(
    hitext()
        .use(hitext.gen.newlines, {
            html: {
                open: ({ line }) => `<span title="line #${line}">`,
                close: () => '</span>'
            }
        })
        .print('foo\nbar', 'html')
);
// 'foo<span title="line #1">\n</span>foo'

matches(pattern)

const hitext = require('hitext');
const matchPrinter = {
    html: {
        open: () => `<span class="match">`,
        close: () => '</span>'
    }
};

console.log(
    hitext()
        .use(hitext.gen.matches('world'), matchPrinter)
        .print('Hello world! Hello world!', 'html')
);
// Hello <span class="match">world</span>! Hello <span class="match">world</span>!

console.log(
    hitext()
        .use(hitext.gen.matches(/\w+/), matchPrinter)
        .print('Hello world!', 'html')
);
// <span class="match">Hello</span> <span class="match">world</span>!

Build-in printers

html

hitext
    .use(whatever, {
        html: {
            open: () => '<span class="example">',
            close: () => '</span>'
        }
    })
    .printer('html');

tty

hitext
    .use(whatever, {
        tty({ createStyle }) => createStyle('bgWhite', 'red')
    })
    .use(whatever, {
        tty({ createStyleMap }) => createStyleMap({
            foo: 'green',
            bar: ['bgWhite', 'red']
        })
    })
    .use(whatever, {
        tty({ createStyleMap }) => createStyleMap({
            foo: 'green',
            bar: ['bgWhite', 'red']
        }, ({ data }) => {
            // specify the way how to transform data to map key
            // when this argument is not specified `({ data }) => data` is using
            return data.magickField;
        })
    })
    .printer('tty');

License

MIT