JSPM

  • Created
  • Published
  • Downloads 958564
  • Score
    100M100P100Q186006F
  • License MIT

HTML/XML processor

Package Exports

  • posthtml
  • posthtml/lib/api
  • posthtml/lib/parser

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (posthtml) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

PostHTML

npm version Build Status Coverage Status

PostHTML is a tool for transforming HTML/XML with JS plugins. PostHTML itself is very small. It includes only a HTML parser, a HTML node tree API and a node tree stringifier.

All HTML transformations are made by plugins. And these plugins are just small plain JS functions, which receive a HTML node tree, transform it, and return a modified tree.

Usage

Install PostHTML

npm install --save-dev posthtml

Simple example

var posthtml = require('posthtml');

var html = '<myComponent><myTitle>Super Title</myTitle><myText>Awesome Text</myText></myComponent>';

posthtml()
    .use(require('posthtml-custom-elements')())
    .process(html/*, options */)
    .then(function(result) {
        console.log(result.html);
        // <div class="myComponent"><div class="myTitle">Super Title</div><div class="myText">Awesome Text</div></div>
    });

Сomplex example

var posthtml = require('posthtml');

var html = '<html><body><p class="wow">OMG</p></body></html>';

posthtml([
        require('posthtml-doctype')('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'),
        require('posthtml-to-svg-tags')(),
        require('posthtml-extend-attrs')({
            attrsTree: {
                '.wow' : {
                    id: 'wow_id',
                    fill: '#4A83B4',
                    'fill-rule': 'evenodd',
                    'font-family': 'Verdana'
                }
            }
        })
    ])
    .process(html/*, options */)
    .then(function(result) {
        console.log(result.html);
        // <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
        // <svg xmlns="http://www.w3.org/2000/svg"><text class="wow" id="wow_id" fill="#4A83B4" fill-rule="evenodd" font-family="Verdana">OMG</text></svg>
    });

Gulp plugin for PostHTML

Install gulp-posthtml

npm install --save-dev gulp-posthtml
gulp.task('html', function() {
    var posthtml = require('gulp-posthtml');
    return gulp.src('src/**/*.html')
        .pipe(posthtml([ require('posthtml-custom-elements')() ]/*, options */))
        .pipe(gulp.dest('build/'));
});

PostHTML JSON tree example

input HTML

<a class="animals" href="#">
    <span class="animals__cat" style="background: url(cat.png)">Cat</span>
</a>

Tree in PostHTML (PostHTMLTree)

[{
    tag: 'a',
    attrs: {
        class: 'animals',
        href: '#'
    },
    content: [{
        tag: 'span',
        attrs: {
            class: 'animals__cat',
            style: 'background: url(cat.png)'
        },
        content: ['Cat']
    }]
}]

Create PostHTML plugin

This is a simple function with a single argument

Synchronous plugin example

module.exports = function pluginName(tree) {
    // do something for tree
    tree.match({ tag: 'img' }, function(node) {
        node = Object.assign(node, { attrs: { class: 'img-wrapped' } }});
        return {
            tag: 'span',
            attrs: { class: 'img-wrapper' },
            content: node
        }
    });
};

Classic asynchronous plugin example

var request = request('request');
module.exports = function pluginName(tree, cb) {
    var tasks = 0;
    tree.match({ tag: 'a' }, function(node) {
        // skip local anchors
        if (!/^(https?:)?\/\//.test(node.attrs.href)) {
            return node;
        }
        request.head(node.attrs.href, function (err, resp) {
            if (err) return done();
            if (resp.statusCode >= 400) {
                node.attrs.class += ' ' + 'Erroric';
            }
            if (resp.headers.contentType) {
                node.attrs.class += ' content-type_' + resp.headers.contentType;
            }
            done();
        });
        tasks += 1;
        return node;
    });
    function done() {
        tasks -= 1;
        if (!tasks) cb(null, tree);
    }
};

Promised asynchronous plugin example

import { PostHTML } from 'posthtml';
import request from 'request';

export default tree => {
    return new Promise(resolve => {
        tree.match({ tag: 'user-info' }, (node) => {
            request(`/api/user-info?${node.attrs.dataUserId}`, (err, resp, body) {
                if (!err && body) node.content = PostHTML.parse(body);
                resolve(tree);
            });
        });
    });
};

class PostHTML

#parse ({String} html): {PostHTMLTree}

Parses HTML string into a PostHTMLTree object.

Example

import { PostHTML } from 'posthtml';

PostHTML.parse('<div></div>'); // [{ tag: 'div' }]

.use ({Function} plugin): {PostHTML}

Adds a plugin into the flow.

Example

var posthtml = require('posthtml');
var ph = posthtml()
    .use(function(tree) {
        return { tag: 'div', content: tree };
    });

.process ({String|PostHTMLTree} html, {Object} options): {{tree: PostHTMLTree, html: String}}

Applies all plugins to the incoming html object.

Returns (eventually) an Object with modified html and/or tree.

Example

var ph = posthtml()
    .process('<div></div>'/*, { options }*/);

Options

singleTags

Array tags for extend default list single tags

Default: []

Options { singleTags: ['rect', 'custom'] }

...
<div>
    ...
    <rect>
    <custom>
</div>
closingSingleTag

Option to specify version closing single tags. Accepts values: default, slash, tag.

Default: default

Options { closingSingleTag: 'default' }

<singletag>

Options { closingSingleTag: 'slash' }

<singletag />

Options { closingSingleTag: 'tag' }

<singletag></singletag>
skipParse

Skips input html parsing process.

Default: null

posthtml()
    .use(function(tree) { tree.tag = 'section'; })
    .process({ tag: 'div' }, { skipParse: true })
    .then(function (result) {
        result.tree; // { tag: 'section' }
        result.html; // <section></section>
    });
sync

Try to run plugins synchronously. Throws if some plugins are async.

Default: null

posthtml()
    .use(function(tree) { tree.tag = 'section'; })
    .process('<div>foo</div>', { sync: true })
    .html; // <section>foo</section>

class API

.walk ({function(PostHTMLNode): PostHTMLNode})

Walk for all nodes in tree, run callback.

Example

tree.walk(function(node) {
    let classes = node.attrs && node.attrs.class.split(' ') || [];
    if(classes.includes(className)) {
        // do something for node
        return node;
    }
    return node;
});

.match ({Object|String}, {function(PostHTMLNode): PostHTMLNode|String})

Find subtree in tree, run callback.

Example

tree.match({ tag: 'custom-tag' }, function(node) {
    // do something for node
    return Object.assign(node, {
        tag: 'div',
        attrs: { class: node.tag }
    });
});

Support Array matchers

Example

tree.match([{ tag: 'b' }, { tag: 'strong' }], function(node) {
    var style = 'font-weight: bold;';
    node.tag = 'span';
    node.attrs ? (
        node.attrs.style ? (
            node.attrs.style += style
        ) : node.attrs.style = style;
    ) : node.attrs = { style: style };
    return node
});

.matchClass ({String}, {function(PostHTMLNode): PostHTMLNode})

For each found of class run callback

Example

tree.matchClass('class-for-delete', function(node) {
    // do something for node
    return ''; // delete this node in tree
});

Plugins

Ideas for plugins

Something more? ;)