Git Product home page Git Product logo

posthtml's Introduction

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

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

Check project-stub example with Gulp

PostHTML with Jade engine in Expressjs

Also it's work with other view engine. Callback in app.engine is called by res.render() to render the template code.

app.engine('jade', function (path, options, callback) {
    // PostHTML plugins
    var plugins = [
        require('posthtml-bem')(),
        require('posthtml-textr')({ locale: 'ru'}, [
            require('typographic-ellipses'),
            require('typographic-single-spaces'),
            require('typographic-quotes')
        ])
    ];

    var html = require('jade').renderFile(path, options);

    posthtml(plugins)
        .process(html)
        .then(function (result) {
            if (typeof callback === 'function') {
                var res;
                try {
                    res = result.html;
                } catch (ex) {
                    return callback(ex);
                }
                return callback(null, res);
            }
        });
})
app.set('view engine', 'jade');

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

.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

posthtml's People

Contributors

a avatar awinogradov avatar island205 avatar maltsev avatar phloe avatar qfox avatar rajdee avatar tcotton avatar trysound avatar voischev avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.