Skip to content

Commit

Permalink
Merge f984611 into 8d0e8b7
Browse files Browse the repository at this point in the history
  • Loading branch information
tbranyen committed Nov 21, 2022
2 parents 8d0e8b7 + f984611 commit 9f69e45
Show file tree
Hide file tree
Showing 28 changed files with 1,188 additions and 1,633 deletions.
7 changes: 1 addition & 6 deletions packages/babel-plugin-transform-diffhtml/lib/index.js
Expand Up @@ -135,7 +135,6 @@ export default function({ types: t }) {
const visitor = {
TaggedTemplateExpression(path, plugin) {
let tagName = '';
let strict = false;

if (path.node.tag.type === 'Identifier') {
tagName = path.node.tag.name
Expand All @@ -152,10 +151,6 @@ export default function({ types: t }) {
return;
}

if (tagName === `${plugin.opts.tagName || 'html'}.strict`) {
strict = true;
}

const supplemental = {
attributes: {},
children: {},
Expand Down Expand Up @@ -242,7 +237,7 @@ export default function({ types: t }) {
// serializing later. Using WASM the objects returned have getters which
// are lost to the JSON.stringify call. By using createTree the values
// are plucked and applied to the VTree object.
const root = createTree(Internals.parse(HTML, null, { strict })).childNodes;
const root = createTree(Internals.parse(HTML)).childNodes;
const strRoot = JSON.stringify(root.length === 1 ? root[0] : root);
const vTree = babylon.parse('(' + strRoot + ')');

Expand Down
2 changes: 1 addition & 1 deletion packages/diffhtml-components/lib/render-component.js
Expand Up @@ -109,7 +109,7 @@ export default function renderComponent(vTree, transaction) {
render(props, state) {
// Always render the latest `rawNodeName` of a VTree in case of
// hot-reloading the cached value above wouldn't be correct.
return createTree(vTree.rawNodeName(props, state));
return createTree(RawComponent(props, state));
}

/** @type {VTree | null} */
Expand Down
9 changes: 4 additions & 5 deletions packages/diffhtml-components/test/component.js
Expand Up @@ -244,11 +244,12 @@ describe('Component', function() {
strictEqual(componentVTree.rawNodeName, TestComponent);
});

it('will associate the whitespace from the start of a fragment', () => {
it('will associate the first element from the start of a fragment', () => {
class TestComponent extends Component {
render() {
return html`
<div />
<p />
`;
}
}
Expand All @@ -257,8 +258,6 @@ describe('Component', function() {
innerHTML(this.fixture, TestComponent);

const componentVTree = ComponentTreeCache.get(this.fixture.childNodes[0]);
// FIXME This should be a comment to make it more portable. Although text
// will work for now.
strictEqual(this.fixture.childNodes[0].nodeName, '#text');
strictEqual(componentVTree.rawNodeName, TestComponent);
});
Expand Down Expand Up @@ -617,7 +616,7 @@ describe('Component', function() {

const instance = this.fixture.querySelector('custom-component');

strictEqual(instance.shadowRoot.childNodes[1].outerHTML, '<div>Hello world</div>');
strictEqual(instance.shadowRoot.childNodes[0].outerHTML, '<div>Hello world</div>');
strictEqual(this.fixture.innerHTML, '<div><custom-component></custom-component></div>');
});

Expand All @@ -640,7 +639,7 @@ describe('Component', function() {

const instance = this.fixture.querySelector('custom-component');

strictEqual(instance.shadowRoot.childNodes[1].outerHTML, '<div>Hello world</div>');
strictEqual(instance.shadowRoot.childNodes[0].outerHTML, '<div>Hello world</div>');
strictEqual(this.fixture.innerHTML, '<custom-component></custom-component>');
});

Expand Down
10 changes: 5 additions & 5 deletions packages/diffhtml-components/test/integration/web-component.js
Expand Up @@ -53,7 +53,7 @@ describe('Web Component', function() {

const instance = this.fixture.querySelector('custom-component');

equal(instance.shadowRoot.childNodes[1].outerHTML, '<div>Hello world</div>');
equal(instance.shadowRoot.childNodes[0].outerHTML, '<div>Hello world</div>');
equal(this.fixture.innerHTML, '<custom-component></custom-component>');
});

Expand All @@ -71,7 +71,7 @@ describe('Web Component', function() {

const instance = this.fixture.querySelector('custom-component');

equal(instance.shadowRoot.childNodes[1].outerHTML, '<div>Hello world</div>');
equal(instance.shadowRoot.childNodes[0].outerHTML, '<div>Hello world</div>');
equal(this.fixture.innerHTML, '<div><custom-component></custom-component></div>');
});

Expand All @@ -91,7 +91,7 @@ describe('Web Component', function() {

const instance = this.fixture.querySelector('custom-component');

equal(instance.shadowRoot.childNodes[1].outerHTML, '<div>Hello world</div>');
equal(instance.shadowRoot.childNodes[0].outerHTML, '<div>Hello world</div>');
equal(this.fixture.innerHTML, '<custom-component></custom-component>');
});

Expand Down Expand Up @@ -217,7 +217,7 @@ describe('Web Component', function() {

const instance = this.fixture.querySelector('custom-component');

equal(instance.shadowRoot.childNodes[1].outerHTML, '<div>Hello world</div>');
equal(instance.shadowRoot.childNodes[0].outerHTML, '<div>Hello world</div>');
equal(this.fixture.innerHTML, '<div><custom-component></custom-component></div>');
});

Expand Down Expand Up @@ -301,7 +301,7 @@ describe('Web Component', function() {
const inner = this.fixture.querySelector('inner-component');

equal(
instance.shadowRoot.childNodes[1].outerHTML,
instance.shadowRoot.childNodes[0].outerHTML,
'<div><slot></slot></div>',
);

Expand Down
23 changes: 16 additions & 7 deletions packages/diffhtml-middleware-linter/lib/index.js
@@ -1,30 +1,39 @@
const { assign, keys } = Object;
const { isArray } = Array;

/**
* @see https://htmlhint.com/docs/user-guide/list-rules
*/
const defaults = {
"tagname-lowercase": true,
// Doctype and Head
"doctype-first": true, // requires parser change
"doctype-html5": true, // requires parser change
"html-lang-require": true, // requires parser change
"head-script-disabled": true,
"style-disabled": false,
"script-disabled": false,
"title-require": true,

// Attributes
"attr-lowercase": true,
"attr-no-duplication": true, // requires parser change
"attr-no-unnecessary-whitespace": true, // requires parser change
"attr-value-double-quotes": true, // requires parser change
"attr-value-not-empty": false,
"attr-no-duplication": true, // requires parser change
"doctype-first": true, // requires parser change
"tag-pair": true, // requires parser change
"empty-tag-not-self-closed": true, // requires parser change
"spec-char-escape": true, // requires parser change
"tagname-lowercase": true,
"id-unique": true,
"src-not-empty": true,
"title-require": true,
"alt-require": true,
"doctype-html5": true, // requires parser change
"id-class-value": "dash",
"style-disabled": false,
"inline-style-disabled": false,
"inline-script-disabled": false,
"space-tab-mixed-disabled": "space", // requires parser change
"id-class-ad-disabled": false, // tbd
"href-abs-or-rel": false, // tbd
"attr-unsafe-chars": true,
"head-script-disabled": true,
};

const unsafeRegexp = /[\u0000-\u0009\u000b\u000c\u000e-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
Expand Down
2 changes: 2 additions & 0 deletions packages/diffhtml-static-sync/sync.js
Expand Up @@ -82,6 +82,8 @@ function open() {
) {
const children = html(markup);

console.log(children, markup);

if (children.childNodes.length > 1) {
outerHTML(document.documentElement, children.childNodes[1]);
}
Expand Down
38 changes: 20 additions & 18 deletions packages/diffhtml-website/components/layout.js
Expand Up @@ -36,27 +36,29 @@ module.exports = ({ path, page, pages, content }) => html`
</layer>
<layer id="main">
<div class="open-menu"></div>
<header>
<h1>
<a href="/"><img width="120" height="51" src="./images/diffhtml-logo-fit.png"></a>
<div>
<p class="name">diffHTML</p><sub>v${version}</sub>
<p>An easy-to-use Virtual DOM built for the web!</p>
</div>
</h1>
</header>
<div class="page-content">
<div class="open-menu"></div>
<header>
<h1>
<a href="/"><img width="120" height="51" src="./images/diffhtml-logo-fit.png"></a>
<div>
<p class="name">diffHTML</p><sub>v${version}</sub>
<p>An easy-to-use Virtual DOM built for the web!</p>
</div>
</h1>
</header>
<hr />
<hr />
<section id="content">${content}</section>
<section id="content">${content}</section>
<a
href=${`https://github.com/tbranyen/diffhtml/edit/master/packages/diffhtml-website/pages/${path.replace('.html', '.md')}`}
id="edit-on-github"
>
Edit on GitHub &nbsp; <span class="fa fa-github"></span>
</a>
<a
href=${`https://github.com/tbranyen/diffhtml/edit/master/packages/diffhtml-website/pages/${path.replace('.html', '.md')}`}
id="edit-on-github"
>
Edit on GitHub &nbsp; <span class="fa fa-github"></span>
</a>
</div>
<footer>
<a target="_blank" href="https://twitter.com/tbranyen" style="text-decoration: none;">
Expand Down
3 changes: 2 additions & 1 deletion packages/diffhtml-website/config.json
Expand Up @@ -22,7 +22,8 @@

"Parser": ["parser.html", {
"Options": "#options",
"Dynamic values": "#dynamic-values"
"Dynamic values": "#dynamic-values",
"Rust WASM": "#rust-wasm"
}],

"Middleware": ["middleware.html", {
Expand Down
12 changes: 7 additions & 5 deletions packages/diffhtml-website/pages/api.md
@@ -1,12 +1,14 @@
# Core API

The

This documentation covers the core public API. All methods and internals work
in the browser and directly in [Node.js](https://nodejs.org/en/) with or without
[jsdom](https://github.com/jsdom/jsdom).

**Terminology:**

- **VTree**: You will see them mentioned throughout the documentation. They are
- **VTree**: The internal VDOM structure. They are
JavaScript objects that represent a DOM node. They store information such as
the tagName, what the childNodes are, and more. A reference to a VTree can get
you access to the DOM node it represents. They are used throughout the
Expand Down Expand Up @@ -417,7 +419,7 @@ passing a config object to `innerHTML`, `outerHTML`, and `toString`.

In the case of query string and environment variables, uppercase the variables
and prefix with `DIFF_`. So `inner` becomes `DIFF_INNER`. For `parser` use a
JSON string: `JSON.stringify({ parser: { strict: true } })`.
JSON string: `JSON.stringify({ parser: { rawElements: ['div'] } })`.

- [`inner`](#options-inner)
- [`tasks`](#options-tasks)
Expand Down Expand Up @@ -534,8 +536,8 @@ innerHTML(document.body, `Some value`, {

### <a href="#options-parser">parser `Object`</a>

These options modify the parser by making it more strict or changing which
elements are treated as block or self closing.
These options modify the parser by changing which elements are treated as
block or self closing.

[Learn more about these options](/parser.html#options)

Expand All @@ -548,7 +550,7 @@ import { innerHTML } from 'diffhtml';

innerHTML(document.body, `
<h1>Hello world</h2>
`, { parser: { strict: true } });
`, { parser: { rawElements: ['div'] } });
```

---
2 changes: 1 addition & 1 deletion packages/diffhtml-website/pages/index.md
Expand Up @@ -13,7 +13,7 @@ approachable to new programmers, intermediates, and professionals.
- ESM/CJS/UMD + Minified ES5 builds
- Middleware
- Efficient Virtual DOM
- Object pooling to optimize GC
- Object pooling and custom HTML parser to optimize GC
- Strict mode TypeScript via checkJS

<a name="getting-started"></a>
Expand Down
75 changes: 18 additions & 57 deletions packages/diffhtml-website/pages/parser.md
Expand Up @@ -2,16 +2,21 @@

One of the best features of diffHTML is the parser. This drives the compiling
of declarative markup and supports a variety of syntaxes. You can make compound
documents that are comprised of HTML, SVG, or XML. The result is a JSX-like
object which is used by the core engine and the Babel transform.
documents that are comprised of HTML, SVG, or XML. The result is a VTree which
makes it equivalent to the `createTree` function.

When you use `innerHTML`, `outerHTML`, or `html` and pass markup, it will run
through this very fast and efficient parser. Usually production code does not
run the parser. You will pre-compile your markup using the [Babel
transform](/tools.html#babel-transform).
Usually production code does not run the parser. You will pre-compile your markup
using the [Babel transform](/tools.html#babel-transform) that also conveniently
uses the same parser to ensure parity.

The parser can read full HTML documents including doctype, html/head/body/title
etc tags, unwrapped fragments, and more!
The built in parser can read full HTML documents including comments, doctype,
html/head/body/title page tags, multiple unwrapped top-level root elements,
and has support for optional tags. It even supports nested markup within tags,
such as <code>srcdoc="<some markup />"</code> in <code>&lt;iframe/&gt;</code>.

While the parser works for most use cases out-of-the-box, you may want to use
something else. The parser is fully overrieable and allows for any string-based
input, so long as it can be compiled to a tree structure.

**Using with innerHTML:**

Expand Down Expand Up @@ -113,56 +118,12 @@ console.log(Internals.parse(`

## <a href="#options">Options</a>

The parser is somewhat configurable, allowing you to opt into a strict-mode for
erroring if invalid markup is passed. This could be useful to pair with the
[HTML Linter Middleware](/middleware.html#html-linter).

- [`strict`](#strict-mode) - Toggle strict mode parsing
- [`rawElements`](#block-elements) - Modify the list of elements that have raw values
- [`selfClosingElements`](#self-closing) - Modify the list of elements that can self close

<a name="strict-mode"></a>

---

### <a href="#strict-mode">Strict mode</a>

By default the parser operates in loose-mode which is forgiving of missing
closing tags, poor markup, and other common issues. When opting into strict
mode you will receive errors if you don't properly self close tags, have
mismatched tag names, etc.

```js
import { innerHTML } from 'diffhtml';

const options = {
parser: {
strict: true,
}
};
The parser is somewhat configurable, allowing you to change the list of self
closing items. This could be useful to pair with the [HTML Linter
Middleware](/middleware.html#html-linter).

// Will be fine since the elements match
innerHTML(document.body, `
<h1>Hello world</h1>
`, options);

// Will throw since the elements do not match
innerHTML(document.body, `
<h1>Hello world</h2>
`, options);
```

Unlike the other two options below, this feature can be configured using the
tagged template [`html`](/api.html#html) directly.

```js
import { html } from 'diffhtml';

// Will throw an error due to the tag mismatch
html.strict`
<p></div>
`;
```
- [`rawElements`](#block-elements) - Modify the list of elements that have text values instead of markup
- [`voidElements`](#self-closing) - Modify the list of elements that can self close

<a name="block-elements"></a>

Expand Down

0 comments on commit 9f69e45

Please sign in to comment.