island205 / posthtml

PostHTML is a tool to transform HTML/XML with JS plugins. By http://theprotein.io team

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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-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);
        // <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

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/'));
});

Check project-stub example with Gulp

Plugins

Ideas for plugins

Something more? ;)

Helpers

Dependency

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: [
        '\n    ',
            {
            tag: 'span',
            attrs: {
                class: 'animals__cat',
                style: 'background: url(cat.png)'
            },
            content: ['Cat']
        },
        '\n'
    ]
}]

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 { toTree } from 'posthtml/lib/api';
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 = toTree(body);
                resolve(tree);
            });
        });
    });
};

class PostHTML

.parse()

Arguments: {String} html

Parses HTML string into a PostHTMLTree object.

Returns: {PostHTMLTree}

.use()

Arguments: {Function} plugin

Adds a plugin into the flow.

Example

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

.process()

Arguments: {String|PostHTMLTree} html[, {Object} options]

Applies all plugins to the incoming html object.

Returns: {{tree: PostHTMLTree, html: String}}

(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()

Arguments: {function(PostHTMLNode|String): PostHTMLNode|String}

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()

Arguments: {Object|String|RegExp}, {function(PostHTMLNode|String): 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
});

License

MIT

About

PostHTML is a tool to transform HTML/XML with JS plugins. By http://theprotein.io team


Languages

Language:JavaScript 90.2%Language:HTML 9.8%