Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

posthtml

Package Overview
Dependencies
Maintainers
3
Versions
55
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

posthtml - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

23

CHANGELOG.md

@@ -0,1 +1,24 @@

<a name"0.4.0"></a>
## 0.4.0 (2015-10-03)
#### Bug Fixes
* **lint:** fix jscsrc ([a534e0a0](https://github.com/posthtml/posthtml/commit/a534e0a0))
* **posthtml:**
* extend new object with api methods on each plugin call ([82e096ea](https://github.com/posthtml/posthtml/commit/82e096ea))
* code style fix ([d1b3484d](https://github.com/posthtml/posthtml/commit/d1b3484d))
* code style fix ([26e6d7e3](https://github.com/posthtml/posthtml/commit/26e6d7e3))
#### Features
* **api:** handle array matchers ([335b5aac](https://github.com/posthtml/posthtml/commit/335b5aac))
* **docs:**
* write array matchers example in jsdocs/readme ([a14b7675](https://github.com/posthtml/posthtml/commit/a14b7675))
* add logo to readme ([78740c34](https://github.com/posthtml/posthtml/commit/78740c34))
* **lint:** upd jscs ([cef42d5d](https://github.com/posthtml/posthtml/commit/cef42d5d))
* **posthtml:** implement truly sync and async modes, and tests for them ([337243f5](https://github.com/posthtml/posthtml/commit/337243f5))
<a name"0.3.0"></a>

@@ -2,0 +25,0 @@ ## 0.3.0 (2015-09-25)

38

lib/api.js

@@ -20,7 +20,6 @@ 'use strict';

* });
* return tree;
* }
*/
walk: function walk(cb) {
return traverse(this, function (node) {
traverse(this, function (node) {
return cb(node);

@@ -30,4 +29,4 @@ });

/**
* match precondition object for of his search in nodes of tree
* @param {Object} precondition Object for search
* match expression for of his search in nodes of tree
* @param {*} expression Object/String... for search. Array is an enumeration expressions
* @param {Function} cb Callbak function

@@ -43,11 +42,25 @@ * @return {Function} Node in callback

* });
* return tree;
*
* // Array matchers
* 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
* });
* }
*/
match: function match(precondition, cb) {
return this.walk(function (node) {
if (compare(precondition, node)) {
return cb(node);
match: function match(expression, cb) {
Array.isArray(expression) ? this.walk(function (node) {
for (var i = 0, len = expression.length; i < len; i++) {
if (compare(expression[i], node)) return cb(node);
}
return node;
}) : this.walk(function (node) {
if (compare(expression, node)) return cb(node);
return node;
});

@@ -59,3 +72,3 @@ },

* @param {Function} cb Callbak function
* @return {Function} Node in callback
* @return {Function} Node in callback
*

@@ -68,8 +81,7 @@ * Examples use:

* });
* return tree;
* }
*/
matchClass: function matchClass(className, cb) {
return this.match({ attrs: { 'class': true } }, function (node) {
var classes = node.attrs['class'].split(' ') || [];
this.match({ attrs: { 'class': true } }, function (node) {
var classes = node.attrs['class'].split(' ');
if (classes.includes(className)) {

@@ -76,0 +88,0 @@ return cb(node);

@@ -51,4 +51,2 @@ /*jshint -W082 */

if (isEmpty(buf)) buf = { content: '' };
bufArray.push(buf);

@@ -95,3 +93,3 @@ },

toHtml: function toHtml(tree) {
var options = arguments[1] === undefined ? {} : arguments[1];
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

@@ -104,3 +102,3 @@ /**

* default: `<br>`
* slash: `<br/>`
* slash: `<br />`
* tag: `<br></br>`

@@ -144,3 +142,3 @@ *

}
if (typeof node.tag === 'boolean' && !node.tag) return node.content || '';
if (typeof node.tag === 'boolean' && !node.tag) return node.content;
var tag = node.tag || 'div';

@@ -147,0 +145,0 @@ if (singleTags[tag]) {

@@ -15,8 +15,12 @@ 'use strict';

var Posthtml = (function () {
function Posthtml() {
var plugins = arguments[0] === undefined ? [] : arguments[0];
exports['default'] = function (plugins) {
return new PostHTML(plugins);
};
_classCallCheck(this, Posthtml);
var PostHTML = (function () {
function PostHTML() {
var plugins = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
_classCallCheck(this, PostHTML);
this.plugins = plugins;

@@ -26,8 +30,15 @@ }

/**
* Checks the argument to be a Promise (or thenable) object.
*
* @param {*} p - Target object to test
* @returns {Boolean}
*/
/**
* Parse html to json tree
* @param {String} html htmltree
* @return {String} json jsontree
* @param {String} html htmltree
* @returns {PostHTMLTree} json jsontree
*/
Posthtml.prototype.parse = function parse(html) {
PostHTML.parse = function parse(html) {
return _parserJs.toTree(html);

@@ -37,7 +48,9 @@ };

/**
* use plugins
* @param {function} plugin posthtml().use(plugin());
* Use plugin
*
* @param {Function} plugin - PostHTML plugin to register
* @returns {PostHTML}
*/
Posthtml.prototype.use = function use(plugin) {
PostHTML.prototype.use = function use(plugin) {
this.plugins.push(plugin);

@@ -48,43 +61,124 @@ return this;

/**
* @param {String} tree html/json tree
* @param {Object} options Options obj
* @return {Object} result
* @param {String|PostHTMLTree} tree - html/json tree
* @param {?Object} options - Options object
* @param {?Boolean} options.skipParse - to prevent parsing incoming tree
* @param {?Boolean} options.sync - to run plugins syncronously, will throw if there are async plugins
* @returns {Promise<{html: String, tree: PostHTMLTree}>|{html: String, tree: PostHTMLTree}} - result
*/
Posthtml.prototype.process = function process(tree) {
PostHTML.prototype.process = function process(tree) {
var _this = this;
var options = arguments[1] === undefined ? {} : arguments[1];
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
return new Promise(function (resolve) {
tree = options.skipParse ? tree : PostHTML.parse(tree);
tree.options = options;
tree = options.skipParse ? tree : _this.parse(tree);
tree.options = options;
// sync mode
if (options.sync === true) {
this.plugins.forEach(function (plugin) {
apiExtend(tree);
for (var key in _apiJs2['default']) {
tree[key] = _apiJs2['default'][key];
}
_this.plugins.forEach(function (plugin) {
var result = plugin(tree);
if (result) {
tree = result;
var result = undefined;
if (plugin.length === 2 || isPromise(result = plugin(tree))) {
throw new Error('Can’t process synchronously because of async plugin: ' + plugin.name);
}
// return the previous tree unless result is filled
tree = result || tree;
});
resolve({
return {
html: _parserJs.toHtml(tree),
tree: tree
};
}
// async mode
var i = 0,
next = function next(res, cb) {
// all plugins called
if (_this.plugins.length <= i) {
cb(null, res);
return;
}
// little helper to go to the next iteration
var _next = function _next(pluginResult) {
return next(pluginResult || res, cb);
};
// (re)extend the object
apiExtend(res);
// call next
var plugin = _this.plugins[i++];
if (plugin.length === 2) {
plugin(res, function (err, pluginResult) {
if (err) return cb(err);
_next(pluginResult);
});
return;
}
// sync and promised plugins
var err = null;
var pluginResult = tryCatch(function () {
return plugin(res);
}, function (e) {
return err = e;
});
if (err) {
cb(err);
return;
}
if (isPromise(pluginResult)) {
pluginResult.then(_next)['catch'](cb);
return;
}
_next(pluginResult);
};
return new Promise(function (resolve, reject) {
next(tree, function (err, tree) {
if (err) return reject(err);
resolve({
html: _parserJs.toHtml(tree),
tree: tree
});
});
});
};
return Posthtml;
return PostHTML;
})();
exports['default'] = function (plugins) {
return new Posthtml(plugins);
};
exports.PostHTML = PostHTML;
function isPromise(p) {
return p instanceof Promise || typeof p === 'object' && p.then && p['catch'];
}
module.exports = exports['default'];
/**
* Simple tryCatch helper
*
* @param {Function} tryFn - try block
* @param {Function} catchFn - catch block
* @returns {?*} - result if exists
*/
function tryCatch(tryFn, catchFn) {
var res = undefined;
try {
res = tryFn();
} catch (e) {
catchFn(e);
}
return res;
}
function apiExtend(tree) {
tree.match = _apiJs2['default'].match;
tree.matchClass = _apiJs2['default'].matchClass;
tree.walk = _apiJs2['default'].walk;
}
{
"name": "posthtml",
"version": "0.3.0",
"description": "HTML/XML post processor",
"version": "0.4.0",
"description": "HTML/XML processor",
"keywords": [

@@ -33,2 +33,4 @@ "html",

"chai": "^3.0.0",
"chai-as-promised": "^5.1.0",
"chai-subset": "^1.1.0",
"conventional-changelog": "0.0.17",

@@ -39,3 +41,3 @@ "gulp": "^3.9.0",

"isparta": "^3.0.3",
"jscs": "^2.0.0",
"jscs": "^2.1.1",
"jshint": "^2.8.0",

@@ -53,3 +55,3 @@ "mocha": "^2.2.5",

"coverage": "babel-node node_modules/.bin/isparta cover --report text --report html --report lcov node_modules/.bin/_mocha",
"lint": "jshint . && jscs .",
"lint": "jshint . && jscs -v .",
"release-patch": "mversion patch",

@@ -56,0 +58,0 @@ "release-minor": "mversion minor",

# PostHTML
[![npm version](https://badge.fury.io/js/posthtml.svg)](http://badge.fury.io/js/posthtml)
[![Build Status](https://travis-ci.org/posthtml/posthtml.svg?branch=master)](https://travis-ci.org/posthtml/posthtml)
[![Build Status](https://travis-ci.org/posthtml/posthtml.svg?branch=master)](https://travis-ci.org/posthtml/posthtml?branch=master)
[![Coverage Status](https://coveralls.io/repos/posthtml/posthtml/badge.svg?branch=master)](https://coveralls.io/r/posthtml/posthtml?branch=master)
<img align="right" width="220" height="200" title="PostHTML logo" src="http://posthtml.github.io/posthtml/logo.svg">
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.

@@ -65,2 +67,3 @@

#### Install [gulp-posthtml](https://www.npmjs.com/package/gulp-posthtml)
```

@@ -71,13 +74,148 @@ npm install --save-dev gulp-posthtml

```javascript
gulp.task('html', function () {
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/') );
.pipe(posthtml([ require('posthtml-custom-elements')() ]/*, options */))
.pipe(gulp.dest('build/'));
});
```
## Options
## PostHTML JSON tree example
#### `singleTags`
__input HTML__
```html
<a class="animals" href="#">
<span class="animals__cat" style="background: url(cat.png)">Cat</span>
</a>
```
__Tree in PostHTML (PostHTMLTree)__
```javascript
[{
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
```javascript
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
```javascript
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
```javascript
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
```javascript
import { PostHTML } from 'posthtml';
PostHTML.parse('<div></div>'); // [{ tag: 'div' }]
```
### .use ({Function} plugin): {PostHTML}
Adds a plugin into the flow.
### Example
```javascript
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
```javascript
var ph = posthtml()
.process('<div></div>'/*, { options }*/);
```
#### Options
##### `singleTags`
Array tags for extend default list single tags

@@ -99,3 +237,3 @@

#### `closingSingleTag`
##### `closingSingleTag`
Option to specify version closing single tags.

@@ -115,3 +253,3 @@ Accepts values: `default`, `slash`, `tag`.

```html
<singletag/>
<singletag />
```

@@ -126,59 +264,37 @@

## PostHTML JSON tree example
##### `skipParse`
Skips input html parsing process.
__input HTML__
```html
<a class="animals" href="#">
<span class="animals__cat" style="background: url(cat.png)">Cat</span>
</a>
```
__Default__: `null`
__Tree in PostHTML__
```js
[{
tag: 'a',
attrs: {
class: 'animals',
href: '#'
},
content: [{
tag: 'span',
attrs: {
class: 'animals__cat',
style: 'background: url(cat.png)'
},
content: ['Cat']
}]
}]
```javascript
posthtml()
.use(function(tree) { tree.tag = 'section'; })
.process({ tag: 'div' }, { skipParse: true })
.then(function (result) {
result.tree; // { tag: 'section' }
result.html; // <section></section>
});
```
## Create PostHTML plugin
##### `sync`
Try to run plugins synchronously. Throws if some plugins are async.
This is a simple function with a single argument
__Default__: `null`
### Example plugin
```javascript
module.exports = function (tree) {
posthtml()
.use(function(tree) { tree.tag = 'section'; })
.process('<div>foo</div>', { sync: true })
.html; // <section>foo</section>
```
// 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
}
});
return tree;
}
```
## class API
## API
### Walk
### .walk ({function(PostHTMLNode): PostHTMLNode})
Walk for all nodes in tree, run callback.
#### Example use
#### Example
```javascript

@@ -195,11 +311,30 @@ tree.walk(function(node) {

### Match
### .match ({Object|String}, {function(PostHTMLNode): PostHTMLNode|String})
Find subtree in tree, run callback.
#### Example use
#### Example
```javascript
tree.match({ tag: 'custom-tag' }, function(node) {
// do something for node
var tag = node.tag;
node = Object.assign(node, { tag: 'div', attrs: { class: tag } }});
return Object.assign(node, {
tag: 'div',
attrs: { class: node.tag }
});
});
```
Support Array matchers
#### Example
```javascript
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

@@ -209,6 +344,7 @@ });

### matchClass
### .matchClass ({String}, {function(PostHTMLNode): PostHTMLNode})
For each found of class run callback
#### Example use
#### Example
```javascript

@@ -226,8 +362,11 @@ tree.matchClass('class-for-delete', function(node) {

- [posthtml-custom-elements](https://npmjs.com/package/posthtml-custom-elements) — Use custom elements now
- [posthtml-style-to-file](https://npmjs.com/package/posthtml-style-to-file) — Save HTML style nodes and attributes to CSS file
- [posthtml-doctype](https://npmjs.com/package/posthtml-doctype) — Extend html tags doctype
- [posthtml-to-svg-tags](https://github.com/theprotein/posthtml-to-svg-tags) — Convert html tags to svg equals
- [posthtml-extend-attrs](https://github.com/theprotein/posthtml-extend-attrs) — Extend html tags attributes with custom data and attributes
- [posthtml-modular-css](https://github.com/admdh/posthtml-modular-css) — Makes css modular
## Ideas for plugins
- [retext](https://github.com/wooorm/retext) — Extensible system for analysing and manipulating natural language
- [posthtml-include](https://github.com/posthtml/posthtml-include) — Include html file

@@ -234,0 +373,0 @@ - [posthtml-imports](https://github.com/posthtml/posthtml-imports) — Support W3C HTML imports

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc