POC rendering via queue
This commit is contained in:
parent
97f876abba
commit
b6748f3be9
2 changed files with 188 additions and 0 deletions
118
packages/astro/test/units/render/jsx.proto.js
Normal file
118
packages/astro/test/units/render/jsx.proto.js
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/**
|
||||||
|
* We take a root as function and we start creating a quue
|
||||||
|
*/
|
||||||
|
export function orderRoot(root) {
|
||||||
|
const queue = [root];
|
||||||
|
let result = [];
|
||||||
|
let previousNode;
|
||||||
|
// we apply a do/while because we need to process the root first
|
||||||
|
do {
|
||||||
|
// we pop elements from the back
|
||||||
|
let currentNode = queue.pop();
|
||||||
|
if (Array.isArray(currentNode.children)) {
|
||||||
|
// if we have children, we fill the queue
|
||||||
|
queue.push(...currentNode.children);
|
||||||
|
const newNode = {};
|
||||||
|
if (currentNode.node) {
|
||||||
|
newNode.node = currentNode.node;
|
||||||
|
}
|
||||||
|
// we need to create a new data structure were we need to keep track of the parent of each node
|
||||||
|
// the root doesn't have any parent
|
||||||
|
if (previousNode) {
|
||||||
|
newNode.parent = previousNode.node;
|
||||||
|
}
|
||||||
|
// track the previous node
|
||||||
|
previousNode = currentNode;
|
||||||
|
// fill the new node
|
||||||
|
result.push(newNode);
|
||||||
|
} else {
|
||||||
|
// usually here we have leafs and "children" should be just a string
|
||||||
|
const newNode = { content: currentNode.children };
|
||||||
|
if (currentNode.node) {
|
||||||
|
newNode.node = currentNode.node;
|
||||||
|
}
|
||||||
|
if (previousNode) {
|
||||||
|
newNode.parent = previousNode.node;
|
||||||
|
}
|
||||||
|
result.push(newNode);
|
||||||
|
}
|
||||||
|
} while (queue.length > 0);
|
||||||
|
|
||||||
|
return result.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderQueue(queue) {
|
||||||
|
let html = '';
|
||||||
|
let previousParent;
|
||||||
|
while (queue.length > 0) {
|
||||||
|
let element = queue.shift();
|
||||||
|
if (!element.parent) {
|
||||||
|
html = `<${element.node}>${html}</${element.node}>`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!previousParent) {
|
||||||
|
if (element.node) {
|
||||||
|
html += renderElement(element.node, element.content);
|
||||||
|
} else {
|
||||||
|
html += element.content;
|
||||||
|
}
|
||||||
|
previousParent = element.parent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (previousParent === element.node) {
|
||||||
|
if (element.content) {
|
||||||
|
if (element.node) {
|
||||||
|
html += renderElement(element.node, element.content);
|
||||||
|
} else {
|
||||||
|
html += element.content;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html = `<${element.node}>${html}</${element.node}>`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let [side, parent] = renderUntilElement(element, queue, element.parent);
|
||||||
|
previousParent = parent;
|
||||||
|
html += side;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousParent = element.parent;
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderUntilElement(previousElement, iterator, parent) {
|
||||||
|
let html = '';
|
||||||
|
let previousParent;
|
||||||
|
if (previousElement.content) {
|
||||||
|
if (previousElement.node) {
|
||||||
|
html += renderElement(previousElement.node, previousElement.content);
|
||||||
|
} else {
|
||||||
|
html += previousElement.content;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html = renderElement(previousElement.node, html);
|
||||||
|
}
|
||||||
|
while (iterator.length > 0) {
|
||||||
|
let element = iterator.shift();
|
||||||
|
if (element.node === parent) {
|
||||||
|
html = renderElement(element.node, html);
|
||||||
|
previousParent = element.node;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (element.content) {
|
||||||
|
if (element.node) {
|
||||||
|
html += renderElement(element.node, element.content);
|
||||||
|
} else {
|
||||||
|
html += element.content;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html = renderElement(element.node, html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [html, previousParent];
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderElement(node, content) {
|
||||||
|
return `<${node}>${content}</${node}>`;
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from '../../../dist/core/render/index.js';
|
} from '../../../dist/core/render/index.js';
|
||||||
import { createAstroJSXComponent, renderer as jsxRenderer } from '../../../dist/jsx/index.js';
|
import { createAstroJSXComponent, renderer as jsxRenderer } from '../../../dist/jsx/index.js';
|
||||||
import { defaultLogging as logging } from '../../test-utils.js';
|
import { defaultLogging as logging } from '../../test-utils.js';
|
||||||
|
import { orderRoot, renderQueue } from './jsx.proto.js';
|
||||||
|
|
||||||
const createAstroModule = (AstroComponent) => ({ default: AstroComponent });
|
const createAstroModule = (AstroComponent) => ({ default: AstroComponent });
|
||||||
const loadJSXRenderer = () => loadRenderer(jsxRenderer, (s) => import(s));
|
const loadJSXRenderer = () => loadRenderer(jsxRenderer, (s) => import(s));
|
||||||
|
@ -29,6 +30,36 @@ describe('core/render', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('new rendering order', async () => {
|
||||||
|
const Page = createAstroJSXComponent(() => {
|
||||||
|
return jsx('main', {
|
||||||
|
children: [
|
||||||
|
jsx('p', {
|
||||||
|
className: 'n',
|
||||||
|
children: [
|
||||||
|
jsx('span', {
|
||||||
|
children: 'label 1',
|
||||||
|
}),
|
||||||
|
' ',
|
||||||
|
jsx('span', {
|
||||||
|
children: 'label 2',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const ctx = createRenderContext({ request: new Request('http://example.com/') });
|
||||||
|
const response = await renderPage(createAstroModule(Page), ctx, env);
|
||||||
|
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
|
||||||
|
const html = await response.text();
|
||||||
|
console.log(html);
|
||||||
|
expect(html).to.include('<div><p class="n">works</p></div>');
|
||||||
|
});
|
||||||
|
|
||||||
it('Can render slots', async () => {
|
it('Can render slots', async () => {
|
||||||
const Wrapper = createComponent((result, _props, slots = {}) => {
|
const Wrapper = createComponent((result, _props, slots = {}) => {
|
||||||
return render`<div>${renderSlot(result, slots['myslot'])}</div>`;
|
return render`<div>${renderSlot(result, slots['myslot'])}</div>`;
|
||||||
|
@ -117,3 +148,42 @@ describe('core/render', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('new engine', () => {
|
||||||
|
it('orderRoot', () => {
|
||||||
|
const root = {
|
||||||
|
node: 'p',
|
||||||
|
children: [
|
||||||
|
{ node: 'span', children: [{ node: 'a', children: 'I am a link' }] },
|
||||||
|
{
|
||||||
|
node: 'span',
|
||||||
|
children: [
|
||||||
|
{ children: 'I am a text' },
|
||||||
|
{ node: 'strong', children: 'I am strong' },
|
||||||
|
{ node: 'em', children: 'I am em' },
|
||||||
|
{ node: 'u', children: 'I am underline' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const expected = [
|
||||||
|
{ node: 'a', content: 'I am a link', parent: 'span' },
|
||||||
|
{ node: 'span', parent: 'span' },
|
||||||
|
{ content: 'I am a text', parent: 'span' },
|
||||||
|
{ node: 'strong', content: 'I am strong', parent: 'span' },
|
||||||
|
{ node: 'em', content: 'I am em', parent: 'span' },
|
||||||
|
{ node: 'u', content: 'I am underline', parent: 'span' },
|
||||||
|
{ node: 'span', parent: 'p' },
|
||||||
|
{ node: 'p' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const expectedString = `<p><span><a>I am a link</a></span><span>I am a text<strong>I am strong</strong><em>I am em</em><u>I am underline</u></span></p>`;
|
||||||
|
let result = orderRoot(root);
|
||||||
|
|
||||||
|
expect(result).to.deep.equal(expected);
|
||||||
|
|
||||||
|
let rendered = renderQueue(result);
|
||||||
|
|
||||||
|
expect(rendered).to.deep.equal(expectedString);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue