Skip to content

Commit f98c89e

Browse files
committedOct 23, 2022
100% test coverage
1 parent 117b53e commit f98c89e

File tree

7 files changed

+75
-26
lines changed

7 files changed

+75
-26
lines changed
 

‎src/index.js

+24-15
Original file line numberDiff line numberDiff line change
@@ -115,31 +115,19 @@ function processTree(options) {
115115
currentNode.attrs = {};
116116
}
117117

118-
const componentFile = currentNode.attrs[options.attribute] || findPathFromTag(currentNode.tag, options);
118+
const componentPath = getComponentPath(currentNode, options);
119119

120-
if (!componentFile) {
120+
if (!componentPath) {
121121
return currentNode;
122122
}
123123

124-
const componentPath = path.isAbsolute(componentFile) && !currentNode.attrs[options.attribute] ?
125-
componentFile :
126-
path.join(options.root, componentFile);
127-
128-
// Check if file exist only when not using x-tag
129-
if (currentNode.attrs[options.attribute] && !existsSync(componentPath)) {
130-
if (options.strict) {
131-
throw new Error(`[components] The component was not found in ${componentPath}.`);
132-
} else {
133-
return currentNode;
134-
}
135-
}
136-
137124
// console.log(`${++processCounter}) Processing component ${componentPath}`);
138125

139126
let nextNode = parser(readFileSync(componentPath, 'utf8'));
140127

141128
// Set filled slots
142129
setFilledSlots(currentNode, filledSlots, options);
130+
setFilledSlots(nextNode, filledSlots, options);
143131

144132
// Reset previous locals with passed global and keep aware locals
145133
options.expressions.locals = {...options.locals, ...options.aware};
@@ -158,6 +146,7 @@ function processTree(options) {
158146
// Process <yield> tag
159147
const content = match.call(nextNode, {tag: options.yield}, nextNode => {
160148
// Fill <yield> with current node content or default <yield>
149+
console.log(currentNode.content);
161150
return currentNode.content || nextNode.content;
162151
});
163152

@@ -190,6 +179,26 @@ function processTree(options) {
190179
};
191180
}
192181

182+
function getComponentPath(currentNode, options) {
183+
const componentFile = currentNode.attrs[options.attribute];
184+
185+
if (componentFile) {
186+
const componentPath = path.join(options.root, componentFile);
187+
188+
if (!existsSync(componentPath)) {
189+
if (options.strict) {
190+
throw new Error(`[components] The component was not found in ${componentPath}.`);
191+
} else {
192+
return false;
193+
}
194+
}
195+
196+
return componentPath;
197+
}
198+
199+
return findPathFromTag(currentNode.tag, options);
200+
}
201+
193202
function applyPluginsToTree(tree, plugins) {
194203
return plugins.reduce((tree, plugin) => {
195204
tree = plugin(tree);

‎src/slots.js

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function setFilledSlots(currentNode, filledSlots, {fill, slotSeparator}) {
2121

2222
const name = fillNode.tag.split(slotSeparator)[1];
2323

24-
const locals = omit(fillNode.attrs, [name, 'type', 'append', 'prepend', 'aware']);
24+
const locals = omit(fillNode.attrs, ['append', 'prepend', 'aware']);
2525

2626
if (locals) {
2727
each(locals, (value, key, attrs) => {
@@ -58,10 +58,6 @@ function processFillContent(tree, filledSlots, {fill, slotSeparator}) {
5858
match.call(tree, {tag: fill}, fillNode => {
5959
const name = fillNode.tag.split(slotSeparator)[1];
6060

61-
if (!filledSlots[name]) {
62-
filledSlots[name] = {};
63-
}
64-
6561
filledSlots[name].tag = fillNode.tag;
6662
filledSlots[name].attrs = fillNode.attrs;
6763
filledSlots[name].content = fillNode.content;
@@ -90,17 +86,21 @@ function processSlotContent(tree, filledSlots, {slot, slotSeparator}) {
9086

9187
slotNode.tag = false;
9288

93-
if (filledSlots[name]?.rendered) {
89+
if (!filledSlots[name]) {
90+
return slotNode;
91+
}
92+
93+
if (filledSlots[name].rendered) {
9494
slotNode.content = null;
95-
} else if (slotNode.content && filledSlots[name]?.attrs && (typeof filledSlots[name]?.attrs.append !== 'undefined' || typeof filledSlots[name]?.attrs.prepend !== 'undefined')) {
96-
slotNode.content = typeof filledSlots[name]?.attrs.append === 'undefined' ? filledSlots[name]?.content.concat(slotNode.content) : slotNode.content.concat(filledSlots[name]?.content);
95+
} else if (slotNode.content && filledSlots[name].attrs && (typeof filledSlots[name].attrs.append !== 'undefined' || typeof filledSlots[name].attrs.prepend !== 'undefined')) {
96+
slotNode.content = typeof filledSlots[name].attrs.append === 'undefined' ? filledSlots[name].content.concat(slotNode.content) : slotNode.content.concat(filledSlots[name].content);
9797
} else {
98-
slotNode.content = filledSlots[name]?.content;
98+
slotNode.content = filledSlots[name].content;
9999
}
100100

101101
// Set rendered to true so a slot can be output only once,
102102
// when not present "aware" attribute
103-
if (filledSlots[name] && (!filledSlots[name]?.attrs || typeof filledSlots[name].attrs.aware === 'undefined')) {
103+
if (filledSlots[name] && (!filledSlots[name].attrs || typeof filledSlots[name].attrs.aware === 'undefined')) {
104104
filledSlots[name].rendered = true;
105105
}
106106

Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div><slot:name>{{ $slots.name.locals.mySlotLocal }}</slot:name></div>

‎test/templates/layouts/base.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<html>
2-
<head><title>Base Layout</title></head>
2+
<head><title>Base Layout</title><stack name="head"></stack></head>
33
<body>
44
<header><slot:header></slot:header></header>
55
<main><yield></yield></main>

‎test/test-errors.js

+6
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,9 @@ test('Must fail when component is not found in defined namespace with strict mod
5858

5959
await t.throwsAsync(async () => posthtml([plugin({root: './test/templates', strict: true, namespaces: [{name: 'empty-namespace', root: './test/templates/empty-namespace'}]})]).process(actual).then(result => clean(result.html)));
6060
});
61+
62+
test('Must fail when push tag missing name', async t => {
63+
const actual = `<div><push></push></div>`;
64+
65+
await t.throwsAsync(async () => posthtml([plugin({root: './test/templates', strict: true})]).process(actual).then(result => clean(result.html)));
66+
});

‎test/test-locals.js

+9
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,12 @@ test('Must process default, merged and override props', async t => {
7272

7373
t.is(html, expected);
7474
});
75+
76+
test('Must process slot with locals', async t => {
77+
const actual = `<component src="components/slot-with-locals.html"><fill:name mySlotLocal=" Via Slot" prepend>My Local</fill:name></component>`;
78+
const expected = `<div>My Local Via Slot</div>`;
79+
80+
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
81+
82+
t.is(html, expected);
83+
});

‎test/test-stacks.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const test = require('ava');
4+
const plugin = require('../src');
5+
const posthtml = require('posthtml');
6+
const clean = html => html.replace(/(\n|\t)/g, '').trim();
7+
8+
test('Must process stacks and push', async t => {
9+
const actual = `<component src="layouts/base.html"><div>Main content</div><push name="head"><meta name="pushed" content="Content pushed"></push></component>`;
10+
const expected = `<html><head><title>Base Layout</title><meta name="pushed" content="Content pushed"></head><body><header></header><main><div>Main content</div></main><footer>footer content</footer></body></html>`;
11+
12+
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
13+
14+
t.is(html, expected);
15+
});
16+
17+
test('Must prepend push on stack once', async t => {
18+
const actual = `<component src="layouts/base.html"><div>Main content</div><push name="head" prepend once><meta name="pushed" content="Content pushed"></push><push name="head" prepend once><meta name="pushed" content="Content pushed"></push></component>`;
19+
const expected = `<html><head><title>Base Layout</title><meta name="pushed" content="Content pushed"></head><body><header></header><main><div>Main content</div></main><footer>footer content</footer></body></html>`;
20+
21+
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
22+
23+
t.is(html, expected);
24+
});

0 commit comments

Comments
 (0)
Please sign in to comment.