Coder Social home page Coder Social logo

posthtml-render's Introduction

npm node tests coverage

PostHTML

PostHTML Render

Renders a PostHTML Tree to HTML/XML

Install

npm i -D posthtml-render

Usage

NodeJS

import { render } from 'posthtml-render';

const tree = [];

const node = {};

node.tag = 'ul';
node.attrs = { class: 'list' };
node.content = [
 'one',
 'two',
 'three'
].map((content) => ({ tag: 'li', content }));

tree.push(node);

const html = render(tree, options);
<ul class="list">
  <li>one</li>
  <li>two</li>
  <li>three</li>
</ul>

Options

Name Type Default Description
singleTags {Array<String|RegExp>} [] Specify custom single tags (self closing)
closingSingleTag {String} > Specify the single tag closing format
quoteAllAttributes {Boolean} true Put double quotes around all tags, even when not necessary.
replaceQuote {Boolean} true Replaces quotes in attribute values with &quote;.
quoteStyle {0 or 1 or 2} 2 Specify the style of quote arround the attribute values

singleTags

Specify custom single tags (self closing)

{String}

const render = require('posthtml-render')

const tree = [ { tag: 'name' } ]
const options = { singleTags: [ 'name' ] }

const html = render(tree, options)

result.html

<name>

{RegExp}

const render = require('posthtml-render')

const tree = [ { tag: '%=title%' } ]
const options = { singleTags: [ /^%.*%$/ ] }

const html = render(tree, options)

result.html

<%=title%>

closingSingleTag

Specify the single tag closing format

Formats

const render = require('posthtml-render')

const tree = [ { tag: 'img' } ]
'tag'
const html = render(tree, { closingSingleTag: 'tag' })
<custom></custom>
'slash'
const html = render(tree, { closingSingleTag: 'slash' })
<custom />
'default' (Default)
const html = render(tree)
<img>
'closeAs'
const tree = [ {
  tag: 'custom',
  closeAs: 'default' // Available types: `tag` | `slash` | `default`
} ]
const html = render(tree, { closingSingleTag: 'closeAs' })
<custom>

quoteAllAttributes

Specify if all attributes should be quoted.

true (Default)
<i src="index.js"></i>
false
<i src=index.js></i>

replaceQuote

Replaces quotes in attribute values with &quote;.

true (Default)
<img src="<?php echo $foo[&quote;bar&quote;] ?>">
false
<img src="<?php echo $foo["bar"] ?>">

quoteStyle

2 (Default)

Attribute values are wrapped in double quotes:

<img src="https://example.com/example.png" onload="testFunc("test")">
1

Attribute values are wrapped in single quote:

<img src='https://example.com/example.png' onload='testFunc("test")'>
0

Quote style is based on attribute values (an alternative for replaceQuote option):

<img src="https://example.com/example.png" onload='testFunc("test")'>

posthtml-render's People

Contributors

0ctothorp avatar anikethsaha avatar awinogradov avatar chrjean avatar cvrajeesh avatar dependabot[bot] avatar guria avatar hojas avatar island205 avatar kevincox avatar maciej-ka avatar michael-ciniawsky avatar scrum avatar sukkaw avatar voischev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

posthtml-render's Issues

JSON in data attributes have double quotes converted to &quot;

Details

Traced this issue down to attrs and this area in particular;

          let attrValue = object[key];

          if (replaceQuote) {
            attrValue = object[key].replace(/"/g, '&quot;');
          }

          attr += ' ' + key + '="' + attrValue + '"';

Example

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app" data-config="{
        &quot;title&quot;: &quot;This is a test&quot;
    }"></div>
    <script src="/parcel-test.e31bb0bc.js"></script>
</body>

</html>

Reproduction (Code)

package.json

{
  "name": "parcel-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "parcel index.html --out-dir build"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "parcel": "^1.12.4",
    "react": "^17.0.1",
    "react-dom": "^17.0.1"
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';

const root = document.getElementById('app');
const config = JSON.parse(root.dataset.config);

const App = ({config}) => {
    return <h1>{config.title}</h1>
}

ReactDOM.render(<App config={config} />, root);

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app" data-config='{
        "title": "This is a test"
    }'></div>
    <script src="./index.js"></script>
</body>

</html>

Run the example

$ npm run watch

[fix]: parse obj in attrs

input

<button class="button button_theme_alfa-on-white button_view_extra button_size_l button_type_submit button__control i-bem button_js_inited" data-bem="{&quot;button&quot;:{&quot;checkedView&quot;:&quot;extra&quot;}}" role="button" type="submit"><span class="button__text">Войти в интернет</span></button>

output

<button class="button button_theme_alfa-on-white button_view_extra button_size_l button_type_submit button__control i-bem" data-bem="{" button":{"checkedview":"extra"}}"="" role="button" type="submit"><span class="button__text">Войти в интернет</span></button>

PostHTML 0.16 regression with <style>

Can’t add <style> in PostHTML 0.16 regression

Details

Custom plugin:

  let ignorePreload = { script: true, image: true }
  function htmlPlugin(tree) {
    tree.walk(i => {
      if (i.tag === 'link' && i.attrs.rel === 'stylesheet') {
        return [{ tag: 'style', content: [css] }]
      } else if (i.tag === 'link' && ignorePreload[i.attrs.as]) {
        return []
      } else if (i.tag === 'script') {
        return {
          tag: 'script',
          content: js
        }
      } else if (i.attrs && i.attrs.class) {
        return {
          tag: i.tag,
          content: i.content,
          attrs: {
            ...i.attrs,
            class: i.attrs.class
              .split(' ')
              .map(kls => {
                if (!classes[kls]) {
                  process.stderr.write(`Unused class .${kls}\n`)
                  process.exit(1)
                }
                return classes[kls]
              })
              .join(' ')
          }
        }
      } else {
        return i
      }
    })
  }

Error (Logs|Stacks)

No errors. Just lack of <style> compare to 0.15.

Reproduction (Code)

⚠️ Please remember that, with sample code; it's easier to reproduce a bug and much faster to fix it.

🔗 Please refer to a simple code example.

$ git clone https://github.com/ai/sitnik.ru
$ yarn build
$ cat ./dist/ru/index.html
# Has <style>
$ yarn upgrade-interactive --latest
# Update posthtml
$ yarn build
$ cat ./dist/ru/index.html
# No <style>

Environment

ℹ️ Please provide information about your current environment.

OS node npm/yarn package
Fedora 16.3 1.22.10 0.16.0

Case sensitivity breaks empty elements

Self closing tags which contain an upper-case character are not recognised as self closing, causing invalid HTML.

const render = require('posthtml-render')

const uppercaseTree = [ { tag: 'IMG' } ]
const lowercaseTree = [ { tag: 'img' } ]

const html1 = render(uppercaseTree) // Returns: <IMG></IMG>
const html2 = render(lowercaseTree) // Returns: <img>

This happens with all empty HTML elements: area, base, br, col, embed, hr, img, input, link,, meta, param, source, track, wbr.

Using [email protected] in Node

Won't render AST straight from the parser...

So I'm using posthtml-parser and posthtml-render.
And render won't render AST coming straight from posthtml-parser.

Details

I tried something simple and this is the result.

https://codesandbox.io/s/crazy-cartwright-7xxmk

Code only

const render = require("posthtml-render").default;
const parser = require("posthtml-parser").default;

const html = `
<div class="min-w-screen min-h-screen bg-gray-200 flex items-center justify-center px-5 py-5">
    <div class="w-full mx-auto rounded-lg bg-white shadow p-5 text-gray-800" style="max-width: 400px">
        <div class="w-full flex mb-4">
            <div class="overflow-hidden rounded-full w-12 h-12">
                <img src="https://uifaces.co/our-content/donated/1H_7AxP0.jpg" alt="">
            </div>
            <div class="flex-grow pl-3">
                <h6 class="font-bold text-md">Joe Blow</h6>
                <p class="text-xs text-gray-600">@joe.blow</p>
            </div>
            <div class="w-12 text-right">
                <i class="mdi mdi-twitter text-blue-400 text-3xl"></i>
            </div>
        </div>
        <div class="w-full mb-4">
            <p class="text-sm">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nam obcaecati laudantium recusandae, debitis eum voluptatem ad, illo voluptatibus temporibus odio provident. Laboriosam accusamus necessitatibus tenetur praesentium ullam voluptates nulla reprehenderit? 🤣</p>
        </div>
        <div class="w-full">
            <p class="text-xs text-gray-500 text-right">Oct 15th 8:33pm</p>
        </div>
    </div>
</div>
`;

console.log(render(parser(html)))
OS node pnpm/parcel package
any v14.16.0 and browser 6.3.0/1.12.5 2.0.0

Node type not exported

The same way postcss-parser exports NodeText and NodeTag, I would export posthtml-render to export Node. This would be helpful when constructing objects for use with posthtml-render.

Details

My use case is as follows:

  1. Manually create an entire Node tree in a TypeScript project (no parsing involved)
  2. Render the tree, return the HTML

I would expect to be able to do something like this:

import { Node, render } from 'posthtml-render';

const node: Node = {
  tag: 'div',
  content: [
    { tag: 'div', content: 'Hi' }
  ]
};

const html = render(node);

Instead, I have to do something like:

import render from 'posthtml-render';

import { NodeText, NodeTag } from 'posthtml-parser';

// re-declare the node union type manually (will be compatible since closeAs is optional)
type Node = NodeText | NodeTag;

const node: Node = {
  tag: 'div',
  content: [
    { tag: 'div', content: 'Hi' }
  ]
};

const html = render(node);

Of course, I could omit the Node type completely and just use an implicit any or object, but it is a better development experience to know the type of the object I'm constructing.

I realize that posthtml-render is mainly just a dependency of posthtml and this use case is probably uncommon, but this would open up some additional uses of the package.

Environment

OS node yarn package
macOS 10.15.7 v14.17.1 v1.22.4 v2.0.6

Note: I had to work around #62 to test the above code sample (change types to dist/index.d.ts in node_modules/posthtml-render/package.json).

Breaking change - node version in bugfix release

Hi, in one project we are using some packages that in the dependency tree use the posthtml-render.

We just noticed our CI/CD pipeline broke because of your change in required node version in the latest bugfix update. package.json changes

Because of legacy (what else :D) we are depending on node 8 so this "bugfix" is quite disruptive. I think that doing this kind of change in a bugfix is a bit too drastic. I would say that even in a minor release it can be a too big change. Especially when some packages are using the caret ^ notation for versions.

Space added to quotes in attribute (with replaceQuote disabled)

So I've got this div right here:

<div role="article" aria-roledescription="email" aria-label='{{ translate "subject" }}' lang="en">

Note that I've changed the default posthtml delimiters to be [[ and ]] so they don't clash with the templating syntax we use down the line. replaceQuote is set to false.

What I expect is to get exactly the same thing after posthtml (except for it maybe changing the outer quotes, I don't really care about that):

<div role="article" aria-roledescription="email" aria-label="{{ translate "subject" }}" lang="en">

However, what I actually get is this:

<div role="article" aria-roledescription="email" aria-label="{{translate " subject"}}" lang="en">

Notice the additional space after the quote, because it seems like posthtml considers the second quote to be the closing tag for the aria-label. Unfortunately, this breaks the template during further processing. I've tried everything, from changing the quoteStyle to adding a custom directive { name: ' translate "subject"', start: '{{', end: '}}' }. But nothing has worked so far.

I know this is quite an odd special case, but I'd very much appreciate some help with this.

TypeScript index.d.ts referenced incorrectly in package.json

Though types are included as dist/index.d.ts, package.json references types/index.d.ts, which is not published.

Details

See the package.json here that references types/index.d.ts: https://unpkg.com/browse/[email protected]/package.json

See types/index.d.ts doesn't exist: https://unpkg.com/browse/[email protected]/types/index.d.ts

See dist/index.d.ts exists: https://unpkg.com/browse/[email protected]/dist/index.d.ts

Reproduction (Code)

npm install [email protected]
cat node_modules/types/index.d.ts
# cat: node_modules/types/index.d.ts: No such file or directory

Note that 1.4.0 does not suffer from this issue:

npm install [email protected]
cat node_modules/lib/index.d.ts # hooray

Possible fixes

Change package.json

It seems like simply changing package.json to have "types": "dist/index.d.ts" would be the answer, but that may cause issues when developing locally with an unbuilt package using npm link as the types would exist in types/index.d.s instead of the referenced dist/index.d.ts.

Publish types/

The build system would have to be changed to not build dist/index.d.ts, and the publish process would have to include types/. I did a quick check to see of .npmignore was ignoring types/, but its not, so I'm curious as to why this isn't already published...

Environment

OS node yarn package
macOS 10.15.7 v14.17.1 v1.22.4 v2.0.6

options dose not working

const render = require('posthtml-render');

let html = '<div>www<span>fff</div>';

let res = render(html, {
    closingSingleTag: 'tag',
});
console.log(res); // <div>www<span>fff</div>

[fix]: php code sometimes gets mangled

<img src='<?php echo $foo["bar"] ?>'>
<img src='<?php echo isset($foo['bar']) ? $foo['bar'] : ""; ?>'>

gets turned into:

<img src="<?php echo $foo[&quot;bar&quot;] ?>">
<img src="<?php echo isset($foo[" bar'])="" ?="" $foo['bar']="" :="" "";="">'>

I also have:

        directives: [
            { name: '?php', start: '<', end: '>' }
        ]

in my posthtml options

Changing invalid markup parsing behavior

Hi, I'm trying to parse XML files from a forum that may contain invalid matching tags.

A simple example of what I have to process would be the following syntax :

<a>
  <b>
</a>
    Text
</b>

Since the b closing tag isn't found before a, the posthtml-parser algorithm handles it by bring the closing b tag upward in the tree:

<a>
  <b>
  </b>
</a>
    Text

However, the data is supposed to be understood in the following way:

<a>
  <b>
    Text
  </b>
</a>

Instead of bringing the b closing tag upward, the a closing tag is brought downward, at the first spot where it makes sense.
Is there an option within the parser to make it handle mismatching this way ?

Thank you for your help

[fix]: Component tag handling

Using the posthtml-renderer in combination with Vue is only partially possible, dynamic components that use the component tag are not rendered properly. Those tags that are defined as singular tags are not necessarily singular tags depending on the context that they are beeing used.

It would be good to have a way to exclude a tag from the singluar tags instead of only allowing additions.

Details

  • Parcel.js added vue support in 1.7.0 and posthtml is part of the html pipeline.
  • Vue's component tag can contain content
  • The output of posthtml-renderer stripes the tag content and does not close the tag.
  • I tried my luck with the closingSingleTag option but this sadly removed the content too.
  • I openened up parcel-bundler/parcel/issues/1089

Reproduction (Code)

const render = require('posthtml-render')

// this is the generated AST from within parcel.js
const markup = {
    "tag": "component",
    "attrs": {
        "class": "scriptview-block-content"
    },
    "content": [
        "test"
    ]
}

const html = render(markup, {closingSingleTag: 'tag'})
console.log(html)

Expected (for vue to be readable):

<component class="scriptview-block-content">test</component>

Result:

<component class="scriptview-block-content"></component>
<!-- or without closingSingleTag -->
<component class="scriptview-block-content">

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.