Skip to content

Commit

Permalink
Updates (#2)
Browse files Browse the repository at this point in the history
- Update readme and tests with a bunch of additional examples
- Functions can return a promise
- Can handle nodes with multiple content entries
  • Loading branch information
Jeff Escalante committed Jul 5, 2016
1 parent 5627a52 commit f68f3e3
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
indent_size = 2
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
.DS_Store
.nyc_output
coverage
node_modules
10 changes: 6 additions & 4 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
src
test
contributing.md
.editorconfig
.travis.yml
.gitignore
.editorconfig
.github
.nyc_output
test
coverage
168 changes: 153 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
# PostHTML Content
# PostHTML Content <img align="right" width="220" height="200" title="PostHTML logo" src="http://posthtml.github.io/posthtml/logo.svg">

[![npm](http://img.shields.io/npm/v/posthtml-content.svg?style=flat)](https://badge.fury.io/js/posthtml-content) [![tests](http://img.shields.io/travis/static-dev/posthtml-content/master.svg?style=flat)](https://travis-ci.org/static-dev/posthtml-content) [![dependencies](http://img.shields.io/david/static-dev/posthtml-content.svg?style=flat)](https://david-dm.org/static-dev/posthtml-content) [![coverage](http://img.shields.io/coveralls/static-dev/posthtml-content.svg?style=flat)](https://coveralls.io/github/static-dev/posthtml-content)
[![NPM][npm]][npm-url]
[![Deps][deps]][deps-url]
[![Tests][travis]][travis-url]
[![Coverage][cover]][cover-url]
[![Standard Code Style][style]][style-url]

A plugin for [posthtml](https://github.com/posthtml/posthtml) that allows customized content transforms.
Flexible content transform for posthtml

> **Note:** This project is in early development, and versioning is a little different. [Read this](http://markup.im/#q4_cRZ1Q) for more details.
### Why should you care?
## Why Should You Care?

Rather than having a separate plugin for each kind of content transform you want to be able to do, why not just have one? Parse natural language, markdown, or whatever else you want with a minimalistic and simple interface 🍻

### Installation
## Install

`npm install posthtml-content -S`
```bash
npm i posthtml-content --save
```

> **Note:** This project is compatible with node v6+ only
### Usage
## Usage

Start with some html you want to transform in some way. Add an attribute of your choosing to an element that has contents you want to transform.

```html
<p windoge>Please use windows 98</p>
```

Now pass in an object to posthtml-content. Each key in the object represents an attribute that will be searched for in the html. The value is a function that will get that element's contents as a string, and replace the contents with whatever string is returned from the function.
Now pass in an object to `posthtml-content`. Each key in the object represents an attribute that will be searched for in the html. The value is a function that will get that element's contents as a string, and replace the contents with whatever string is returned from the function.

```js
const content = require('posthtml-content')({
Expand All @@ -40,27 +46,159 @@ The plugin will remove the custom attribute from the element and replace its con
<p>Please use winDOGE 98</p>
```

If you return an [A+ compliant promise](https://promisesaplus.com/) from your content function, it will resolve and work in your templates as well.

You can use external libraries for this as well, no problem. Just make sure you are passing in a function that takes a string and returns a string. You might have to wrap the library function if it doesn't behave like this, but it will work with anything that transforms content.

## Examples

#### Markdown

```html
<p md>Wow, it's **markdown**!</p>
<p md>Wow, it's **Markdown**!</p>
```

```js
const MarkdownIt = require('markdown-it')
const md = new MarkdownIt() // can pass options here
const content = require('posthtml-content')({
md: md.renderInline.bind(md)
const markdown = require('markdown-it')(/* options */)

const plugin = require('posthtml-content')({
md: (md) => markdown.renderInline(md)
})

posthtml([plugin]).process(html)
```

```html
<p>Wow, it's <strong>Markdown</strong>!</p>
```

#### PostCSS

```sugarss
<style postcss>
.test
text-transform: uppercase;
&__hello
color: red;
&__world
color: blue;
</style>
```

```js
const postcss = require('postcss')([ require('postcss-nested')() ])
const options = { parser: require('sugarss'), map: false }

const plugin = require('posthtml-content')({
postcss: (css) => postcss.process(css, options).css
})

posthtml([plugin]).process(html)

```

```html
<p>Wow, it's <strong>markdown</strong>!</p>
<style>
.test {
text-transform: uppercase;
}
.test__hello {
color: red;
}
.test__world {
color: blue;
}
</style>
```

### License & Contributing
#### Babel

```html
<script babel>
const hello = 'Hello World!'
let greeter = {
greet (msg) { alert (msg) }
}
greeter.greet(hello)
</script>
```

```js
const babel = require('babel-core')
const options = { presets: ["es2015"], sourceMaps: false }

const plugin = require('posthtml-content')({
babel: (js) => babel.transform(js, options).code
})

posthtml([plugin]).process(html)
```

```html
<script>
'use strict';
var hello = "Hello World!";
var greeter = {
greet: function greet (msg) {
alert(msg);
};
};
greeter.greet(hello);
</script>
```

#### Return a Promise

```sugarss
<style postcss>
.test
text-transform: uppercase;
&__hello
color: red;
&__world
color: blue;
</style>
```

```js
const postcss = require('postcss')([ require('postcss-nested')() ])
const options = { parser: require('sugarss'), map: false }

const plugin = require('posthtml-content')({
postcss: (css) => {
return postcss.process(css, options).then((res) => res.css)
}
})

posthtml([plugin]).process(html)

```

## License & Contributing

- Details on the license [can be found here](LICENSE.md)
- Details on running tests and contributing [can be found here](contributing.md)

[npm]: https://img.shields.io/npm/v/posthtml-content.svg
[npm-url]: https://npmjs.com/package/posthtml-content

[node]: https://img.shields.io/node/v/gh-badges.svg
[node-url]: https://nodejs.org

[deps]: https://david-dm.org/static-dev/posthtml-content.svg
[deps-url]: https://david-dm.org/static-dev/posthtml-content

[style]: https://img.shields.io/badge/code%20style-standard-yellow.svg
[style-url]: http://standardjs.com/

[travis]: http://img.shields.io/travis/static-dev/posthtml-content.svg
[travis-url]: https://travis-ci.org/static-dev/posthtml-content

[cover]: https://coveralls.io/repos/github/static-dev/posthtml-content/badge.svg?branch=master
[cover-url]: https://coveralls.io/github/static-dev/posthtml-content?branch=master
53 changes: 26 additions & 27 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
const W = require('when')
const intersectKeys = require('./intersectKeys')

function walk (options, nodes) {
nodes.map((node) => {
if (typeof node !== 'object') return
return W.all(nodes.map((node) => {
// We're only looking for tags here
if (typeof node !== 'object') return node

// Also only looking for tags with attributes
if (node.attrs) {
// This function cross-checks to see if any of the attribute keys match
// any of the keys in the user config.
const opt = intersectKeys(options, node.attrs)[0]

if (opt) {
// If it does, remove the attribute from the tag, it's just a marker
delete node.attrs[opt]
node.content = [options[opt](node.content[0])]
// Now for each entry in the node's content, we run the user-provided
// function, which can be a promise or not. We take the results and
// assign them back to the node, then return the modified node
return W.map(node.content, options[opt])
.then((res) => { node.content = res; return node })
}
}
walk(options, node.content)
})
}

// helper: because it's very fast and doesnt need a dependency
function intersectKeys (_a, _b) {
let ai = 0
let bi = 0
let a = Object.keys(_a)
let b = Object.keys(_b)
const result = []

while (ai < a.length && bi < b.length) {
if (a[ai] < b[bi]) {
ai++
} else if (a[ai] > b[bi]) {
bi++
} else {
result.push(a[ai])
ai++
bi++
// If we don't match any attribute keys, return the node as usual
return node
}
}
return result

// Now we recurse through the nested content
return walk(options, node.content)
}))
}

module.exports = (options) => walk.bind(null, options)
module.exports = function PostHTMLContent (options) {
return walk.bind(null, options)
}
20 changes: 20 additions & 0 deletions lib/intersectKeys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = function intersectKeys (_a, _b) {
let ai = 0
let bi = 0
let a = Object.keys(_a)
let b = Object.keys(_b)
const result = []

while (ai < a.length && bi < b.length) {
if (a[ai] < b[bi]) {
ai++
} else if (a[ai] > b[bi]) {
bi++
} else {
result.push(a[ai])
ai++
bi++
}
}
return result
}
24 changes: 18 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
{
"name": "posthtml-content",
"description": "transform contents in any way you want",
"description": "Flexible content transform for posthtml",
"version": "0.0.0",
"author": "static-dev",
"ava": {
"verbose": "true"
},
"bugs": "https://github.com/static-dev/posthtml-content/issues",
"dependencies": {
"when": "^3.7.7"
},
"devDependencies": {
"ava": "0.15.x",
"babel-core": "^6.10.1",
"babel-preset-es2015": "^6.9.0",
"coveralls": "2.x",
"markdown-it": "^7.0.0",
"nyc": "6.x",
"postcss": "^5.0.21",
"postcss-nested": "^1.0.0",
"posthtml": "^0.8.7",
"standard": "7.x"
},
"engines": {
"node": ">= 6.0.0"
"node": ">=6"
},
"homepage": "https://github.com/static-dev/posthtml-content",
"keywords": [
"html",
"posthtml",
"content",
"posthtmlplugin"
],
"license": "MIT",
"main": "lib",
"repository": "static-dev/posthtml-content",
"scripts": {
"test": "ava",
"lint": "standard",
"coverage": "nyc ava",
"coveralls": "nyc --reporter=lcov ava && cat ./coverage/lcov.info | coveralls"
"coveralls": "nyc --reporter=lcov ava && cat ./coverage/lcov.info | coveralls",
"pretest": "standard",
"test": "nyc ava"
}
}
5 changes: 3 additions & 2 deletions test/fixtures/basic.html → test/fixtures/es6.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<title>Hello there!</title>
</head>
<body>
<p>plain text</p>
<p custom>this should be replaced</p>
<article es6>
Article should be placed here.
</article>
</body>
</html>
1 change: 1 addition & 0 deletions test/fixtures/markdown.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!doctype html>
<html>
<head>
<title>Hello there!</title>
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/md.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html>
<head>
<title>Hello there!</title>
</head>
<body>
<h1 md>**Markdown**</h1>
<article md>Markdown is an **easy** to *learn* and *write* language. If you want to learn more about it checkout the following link: [Markdown](https://github.com/markdown-it/markdown-it)</article>
</body>
</html>
Loading

0 comments on commit f68f3e3

Please sign in to comment.