Git Product home page Git Product logo

converter's Introduction

HTML and MD to VanJS Code Converter

This is a library that can convert any MD or HTML snippet into valid VanJS code. The UI version of the code converter is here.

Installation

The library is published as NPM package vanjs-converter.

Run the following command to install the package:

npm install vanjs-converter

To use the NPM package, add this line to your script:

import { htmlToVanCode, mdToVanCode } from "vanjs-converter"

htmlToVanCode: Convert HTML snippet to VanJS Code

Signature

htmlToVanCode(<HTML string>, <options>) => {code: <code>, tags: <tags>, components: <components>}

Example

htmlToVanCode('<div><p>👋Hello</p><ul><li>🗺️World</li><li><a href="https://vanjs.org/">🍦VanJS</a></li></ul></div>', {indent: 4})
/*
The following result will be returned:
{
  code: [
    'div(',
    '    p(',
    '        "👋Hello",',
    '    ),',
    '    ul(',
    '        li(',
    '            "🗺️World",',
    '        ),',
    '        li(',
    '            a({href: "https://vanjs.org/"},',
    '                "🍦VanJS",',
    '            ),',
    '        ),',
    '    ),',
    ')',
  ],
  tags: ["a", "div", "li", "p", "ul"],
  components: [],
}
*/

Using VanJS Components

This is only supported in the converter library, not in the UI. The root cause is html-dom-parser doesn't support case-sensitive parsing on the client side.

The input HTML string can be a mix of HTML elements and custom UI components built with VanJS. To use custom UI components, just specify the component similar to regular HTML tags. For instance, assume we have custom UI components similar to the ones shown in https://vanjs.org/ home page:

const Hello = text => div(
  p("👋Hello"),
  ul(
    li(text),
    li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
  ),
)

const Counter = ({initValue}) => {
  const counter = van.state(initValue)
  return button({onclick: () => ++counter.val}, counter)
}

You can simply specify the input HTML string like this:

<h2>Hello</h2>
<Hello>🗺️World</Hello>
<h2>Counter</h2>
<Counter initValue="1"></Counter>
<Counter initValue="2"></Counter>

which will be converted into the following VanJS code:

h2(
  "Hello",
),
Hello(
  "🗺️World",
),
h2(
  "Counter",
),
Counter({initValue: "1"}),
Counter({initValue: "2"}),

Options

  • indent: Type number. Default 2. Optional. The indent level of the generated VanJS code.

  • spacing: Type boolean. Default false. Optional. The style of the property object in the generated VanJS code. If true, the property object will look like {href: "https://vanjs.org/"}; Otherwise, the property object will look like { href: "https://vanjs.org/" }.

  • skipEmptyText: Type boolean. Default false. Optional. Whether to skip empty text nodes in the generated VanJS code. For instance, the HTML snippet:

    <div>
      <p>👋Hello</p>
      <ul>
        <li>🗺️World</li>
        <li><a href="https://vanjs.org/">🍦VanJS</a></li>
      </ul>
    </div>

    will be converted to:

    div(
      p(
        "👋Hello",
      ),
      ul(
        li(
          "🗺️World",
        ),
        li(
          a({href: "https://vanjs.org/"},
            "🍦VanJS",
          ),
        ),
      ),
    )

    if skipEmptyText is true. But it will be converted to:

    div(
      "\n  ",
      p(
        "👋Hello",
      ),
      "\n  ",
      ul(
        "\n    ",
        li(
          "🗺️World",
        ),
        "\n    ",
        li(
          a({href: "https://vanjs.org/"},
            "🍦VanJS",
          ),
        ),
        "\n  ",
      ),
      "\n",
    )

    if skipEmptyText is false.

  • htmlTagPred: Type (name: string) => boolean. Default s => s.toLowerCase() === s. Optional. A predicate function to check whether a specific tag snippet such as <Counter> should be treated as a native HTML element or a custom UI component built with VanJS. By default, it will be treated as a native HTML element if the letters in the name are all lowercase.

Return Value

A plain object with the following fields:

  • code: A string[] for all lines of the generated VanJS code.
  • tags: A string[] for all HTML tag names used in the generated VanJS code, which can be used in the importing line of tag functions such as:
    const {<tags needs to import>} = van.tags
  • components: A string[] for all custom VanJS components used in the generated VanJS code, which can be used in the importing line such as:
    import {<components needs to import>} from "./my-component-lib.js"

DUMMY

This is only supported in the converter library, not in the UI.

There are 2 special cases while specifying custom VanJS components in the input HTML string. The first special case is that, sometimes, a custom component needs properties being specified in its first argument, even for empty properties {} (e.g.: the Counter component defined in the section above). In this case, you can specify the special DUMMY property as a placeholder. For instance:

<CustomElement DUMMY>content</CustomElement>

will be converted to:

CustomElement({},
  "content",
)

whereas

<CustomElement>content</CustomElement>

will be converted to:

CustomElement(
  "content",
)

The second special case is that, sometimes, a custom VanJS component needs consecutive string arguments. You can achieve that by inserting <DUMMY> element between text pieces. For instance:

<Link>🍦VanJS<DUMMY></DUMMY>https://vanjs.org/</Link>

will be converted to:

Link(
  "🍦VanJS",
  "https://vanjs.org/",
)

mdToVanCode: Convert MD snippet to VanJS Code

Signature

mdToVanCode(<MD string>, <options>) => {code: <code>, tags: <tags>, components: <components>}

Under the hood, there are 2 steps for converting an MD snippet to VanJS code:

  1. Convert the MD string into an HTML string with Marked library.
  2. Convert the HTML string into VanJS code with htmlToVanCode.

Example

mdToVanCode(`👋Hello
* 🗺️World
* [🍦VanJS](https://vanjs.org/)
`)
/*
The following result will be returned:
{
  code: [
    'p(',
    '  "👋Hello",',
    '),',
    'ul(',
    '  li(',
    '    "🗺️World",',
    '  ),',
    '  li(',
    '    a({href: "https://vanjs.org/"},',
    '      "🍦VanJS",',
    '    ),',
    '  ),',
    '),',
  ],
  tags: ["a", "li", "p", "ul"],
  components: [],
}
*/

Note that, you can insert custom HTML snippets, or even custom VanJS components in the input MD string.

Options

  • indent: Type number. Default 2. Optional. The indent level of the generated VanJS code.

  • spacing: Type boolean. Default false. Optional. The style of the property object in the generated VanJS code. If true, the property object will look like {href: "https://vanjs.org/"}; Otherwise, the property object will look like { href: "https://vanjs.org/" }.

  • htmlTagPred: Type (name: string) => boolean. Default s => s.toLowerCase() === s. Optional. A predicate function to check whether a specific tag snippet such as <Counter> represents a native HTML element or a custom UI component built with VanJS. By default, it will be considered a native HTML element if the letters in the name are all lowercase.

  • renderer: Optional. Custom renderer is only supported in the converter library, not in the UI. A custom object used to override how tokens in the MD string are being rendered. The specification of the renderer object can be found in Marked doc. For instance, the renderer object:

    {
      codespan: s => `<Symbol>${s}</Symbol>`,
      link: (href, _unused_title, text) => `<Link>${text}<DUMMY></DUMMY>${href}</Link>`,
    }

    will convert `text` in MD string into Symbol("text") (here Symbol is a custom VanJS component) instead of code("text"), and will convert [text](link) in MD string into Link("text", "link") instead of a({href: "link"}, "text").

Return Value

The same as the return value of htmlToVanCode.

Showroom

The https://vanjs.org/ website is using this library to keep README.md files in sync with their corresponding web pages (source code of the code generation):

converter's People

Contributors

tao-vanjs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

uiforks

converter's Issues

Wrong interpretations of empty lines in converting MD

Hello,
I have and example:

## First

1. 13123
2. qwd

## Second 

as my MD

I am getting:
h2( "First", ), ol( li( "13123", ), li( "qwd", ), ), h2( "Second", ),

I am expecting to see breaking line between "h2" elements and the list. MD converter is ignoring empty lines.

I need some help.

I am developing a Node.js backend project using TypeScript, and my tsconfig.json looks like this:

{
    "compilerOptions": {
        "strict": true,
        "outDir": "js",
        "target": "ESNext",
        "moduleResolution": "NodeNext",
        "module": "NodeNext"
    }
}

I am using the vanjs-converter in the following way:

let { code, tags } = (await import('vanjs-converter')).htmlToVanCode(htmlCode, { skipEmptyText: true });

Then I encounter the following error:
image

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.