posthtml-component 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/.c8rc +3 -0
  2. package/.clintonrc.json +20 -0
  3. package/.editorconfig +19 -0
  4. package/.huskyrc +7 -0
  5. package/.idea/posthtml-components.iml +8 -0
  6. package/.lintstagedrc +4 -0
  7. package/.nycrc +4 -0
  8. package/ava.config.js +5 -0
  9. package/changelog.md +48 -0
  10. package/license +21 -0
  11. package/package.json +52 -0
  12. package/readme.md +809 -0
  13. package/src/attributes.js +55 -0
  14. package/src/find-path.js +119 -0
  15. package/src/index.js +185 -0
  16. package/src/locals.js +105 -0
  17. package/src/slots.js +112 -0
  18. package/src/stacks.js +64 -0
  19. package/test/templates/components/child.html +41 -0
  20. package/test/templates/components/component-append-prepend.html +1 -0
  21. package/test/templates/components/component-locals-json-and-string.html +18 -0
  22. package/test/templates/components/component-locals.html +7 -0
  23. package/test/templates/components/component-mapped-attributes.html +7 -0
  24. package/test/templates/components/component-multiple-slot.html +1 -0
  25. package/test/templates/components/component.html +1 -0
  26. package/test/templates/components/form/index.html +1 -0
  27. package/test/templates/components/modal.html +1 -0
  28. package/test/templates/components/module-with-extend.html +1 -0
  29. package/test/templates/components/module.html +1 -0
  30. package/test/templates/components/nested-one-slot.html +5 -0
  31. package/test/templates/components/nested-one.html +1 -0
  32. package/test/templates/components/nested-three.html +1 -0
  33. package/test/templates/components/nested-two-slot.html +5 -0
  34. package/test/templates/components/nested-two.html +1 -0
  35. package/test/templates/components/parent.html +42 -0
  36. package/test/templates/components/script-locals.html +9 -0
  37. package/test/templates/custom/dark/components/button.html +1 -0
  38. package/test/templates/custom/dark/components/label/index.html +1 -0
  39. package/test/templates/dark/components/button.html +1 -0
  40. package/test/templates/dark/components/label/index.html +1 -0
  41. package/test/templates/dark/layouts/base.html +1 -0
  42. package/test/templates/layouts/base-locals.html +6 -0
  43. package/test/templates/layouts/base-render-slots-locals.html +8 -0
  44. package/test/templates/layouts/base.html +8 -0
  45. package/test/templates/layouts/extend-with-module.html +7 -0
  46. package/test/templates/layouts/extend.html +7 -0
  47. package/test/templates/layouts/playground.html +1 -0
  48. package/test/templates/layouts/slot-condition.html +8 -0
  49. package/test/templates/light/components/button.html +1 -0
  50. package/test/templates/light/layouts/base.html +1 -0
  51. package/test/test-errors.js +39 -0
  52. package/test/test-locals.js +74 -0
  53. package/test/test-nested.js +24 -0
  54. package/test/test-plugins.js +33 -0
  55. package/test/test-slots.js +76 -0
  56. package/test/test-x-tag.js +69 -0
  57. package/xo.config.js +15 -0
@@ -0,0 +1,18 @@
1
+ <script props>
2
+ module.exports = {
3
+ title: 'Default title',
4
+ items: ['default first item', 'default second item'],
5
+ titles: {
6
+ title: 'This is default main title',
7
+ subtitle: 'This is default subtitle',
8
+ suptitle: 'This is default suptitle'
9
+ },
10
+ mycomputed: locals.mycomputed === true ? 'Computed is true' : 'Computed is false'
11
+ }
12
+ </script>
13
+ <div>
14
+ <div>{{ mycomputed }}</div>
15
+ <div><h1>{{ title }}</h1></div>
16
+ <div><each loop="item in items"><span>{{ item }}</span></each></div>
17
+ <div><each loop="t, i in titles"><span>{{ i }}: {{ t }}</span></each></div>
18
+ </div>
@@ -0,0 +1,7 @@
1
+ <script props>
2
+ module.exports = {
3
+ title: 'Default title',
4
+ body: 'Default body'
5
+ }
6
+ </script>
7
+ <div><h1>{{title}}</h1></div><div><slot:body>{{body}}</slot:body></div>
@@ -0,0 +1,7 @@
1
+ <script props>
2
+ module.exports = {
3
+ title: 'Default title',
4
+ body: 'Default body'
5
+ }
6
+ </script>
7
+ <div class="text-dark m-3">{{ title }} {{ body }}</div>
@@ -0,0 +1 @@
1
+ <div><slot:title></slot:title></div><div><slot:body></slot:body></div><div><slot:title></slot:title></div>
@@ -0,0 +1 @@
1
+ <div><slot:title></slot:title></div><div><slot:body></slot:body></div>
@@ -0,0 +1 @@
1
+ <form>My Form</form>
@@ -0,0 +1 @@
1
+ <div>Modal</div>
@@ -0,0 +1 @@
1
+ <div><content></content></div>
@@ -0,0 +1 @@
1
+ <div><content></content></div>
@@ -0,0 +1,5 @@
1
+ <div class="nested-one">
2
+ <div class="nested-one-before"><slot:before></slot:before></div>
3
+ <div class="nested-one-yield"><yield></yield></div>
4
+ <div class="nested-one-after"><slot:after></slot:after></div>
5
+ </div>
@@ -0,0 +1 @@
1
+ <div class="nested-one"><x-nested-two></x-nested-two></div>
@@ -0,0 +1 @@
1
+ <div class="nested-three">Nested works!</div>
@@ -0,0 +1,5 @@
1
+ <div class="nested-two">
2
+ <div class="nested-two-before"><slot:before2></slot:before2></div>
3
+ <div class="nested-two-yield"><yield></yield></div>
4
+ <div class="nested-two-after"><slot:after2></slot:after2></div>
5
+ </div>
@@ -0,0 +1 @@
1
+ <div class="nested-two"><x-nested-three></x-nested-three></div>
@@ -0,0 +1,42 @@
1
+ <script props>
2
+ module.exports = {
3
+ aBoolean: true,
4
+ aString: 'My String',
5
+ aString2: locals.aString2 === 'yes' ? 'I am string 2' : 'I am not string 2',
6
+ anArray: ['one', 'two', 'three'],
7
+ anArray2: ['one2', 'two2', 'three2'],
8
+ anObject: { one: 'One', two: 'Two', three: 'Three'},
9
+ anObject2: { one: 'One2', two: 'Two2', three: 'Three2'}
10
+ };
11
+ </script>
12
+ PARENT:
13
+ <div>
14
+ aBoolean
15
+ value: {{ aBoolean }}
16
+ type: {{ typeof aBoolean }}
17
+
18
+ aString
19
+ value: {{ aString }}
20
+ type: {{ typeof aString }}
21
+
22
+ aString2
23
+ value: {{ aString2 }}
24
+ type: {{ typeof aString2 }}
25
+
26
+ anArray
27
+ value: {{ anArray }}
28
+ type: {{ typeof anArray }}
29
+
30
+ anObject
31
+ value: {{ anObject }}
32
+ type: {{ typeof anObject }}
33
+
34
+ anArray2
35
+ value: {{ anArray2 }}
36
+ type: {{ typeof anArray2 }}
37
+
38
+ anObject2
39
+ value: {{ anObject2 }}
40
+ type: {{ typeof anObject2 }}
41
+ </div>
42
+ <yield></yield>
@@ -0,0 +1,9 @@
1
+ <script props>
2
+ module.exports = {
3
+ title: 'Default title',
4
+ slotsAccessibleViaScript: locals.$slots
5
+ }
6
+ </script>
7
+ {{ slotsAccessibleViaScript }}
8
+ <div>{{ $slots }}</div>
9
+ <div><h1>{{title}}</h1></div><div><slot:filled></slot:filled><slot:notfilled></slot:notfilled></div>
@@ -0,0 +1 @@
1
+ <button class="bg-dark-custom text-light-custom"><yield></yield></button>
@@ -0,0 +1 @@
1
+ <label>My Label</label>
@@ -0,0 +1 @@
1
+ <button class="bg-dark text-light"><yield></yield></button>
@@ -0,0 +1 @@
1
+ <label class="bg-dark text-light">My Dark Label</label>
@@ -0,0 +1 @@
1
+ <html><head><title>Base Dark Layout</title></head><body><main><slot name="content"></slot></main><footer><slot name="footer">footer content</slot></footer></body></html>
@@ -0,0 +1,6 @@
1
+ <script props>
2
+ module.exports = {
3
+ title: 'Default title'
4
+ }
5
+ </script>
6
+ <html><head><title>{{ title }}</title></head><body><main><yield></yield></main><footer><slot:footer></slot:footer></footer></body></html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head><title>Base Render Slots Locals Layout</title></head>
3
+ <body>
4
+ <header>{{{ $slots.header.source }}}</header>
5
+ <main><yield></yield></main>
6
+ <footer>{{{ $slots.footer.source }}}</footer>
7
+ </body>
8
+ </html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head><title>Base Layout</title></head>
3
+ <body>
4
+ <header><slot:header></slot:header></header>
5
+ <main><yield></yield></main>
6
+ <footer><slot:footer>footer content</slot:footer></footer>
7
+ </body>
8
+ </html>
@@ -0,0 +1,7 @@
1
+ <html>
2
+ <head><title>Extend With Module Layout</title></head>
3
+ <body>
4
+ <main><block name="content"></block></main>
5
+ <footer><block name="footer">footer content</block></footer>
6
+ </body>
7
+ </html>
@@ -0,0 +1,7 @@
1
+ <html>
2
+ <head><title>Extend Layout</title></head>
3
+ <body>
4
+ <main><block name="content"></block></main>
5
+ <footer><block name="footer">footer content</block></footer>
6
+ </body>
7
+ </html>
@@ -0,0 +1 @@
1
+ <html><head><title>Playground Layout</title></head><body><main><slot></slot></main><footer><slot name="footer">default footer content</slot></footer></body></html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head><title>Slot Condition Layout</title></head>
3
+ <body>
4
+ <main><yield></yield></main>
5
+ <if condition="$slots.footer?.filled"><footer><slot:footer></slot:footer></footer></if>
6
+ <else><p>There is not footer defined.</p></else>
7
+ </body>
8
+ </html>
@@ -0,0 +1 @@
1
+ <button class="bg-light text-dark"><slot name="content"></slot></button>
@@ -0,0 +1 @@
1
+ <html><head><title>Base Light Layout</title></head><body><main><slot name="content"></slot></main><footer><slot name="footer">footer content</slot></footer></body></html>
@@ -0,0 +1,39 @@
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 fail when namespace is unknown', async t => {
9
+ const actual = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
10
+
11
+ await t.throwsAsync(async () => posthtml([plugin({root: './test/templates', strict: true})]).process(actual).then(result => clean(result.html)));
12
+ });
13
+
14
+ test('Must return node as-is when namespace is unknown with strict mode disabled', async t => {
15
+ const actual = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
16
+ const expected = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
17
+
18
+ const html = await posthtml([plugin({root: './test/templates', strict: false})]).process(actual).then(result => clean(result.html));
19
+
20
+ t.is(html, expected);
21
+ });
22
+
23
+ test('Must return node as-is when namespace is empty with strict mode disabled', async t => {
24
+ const actual = `<div><x-empty-namespace::button>Submit</x-empty-namespace::button></div>`;
25
+ const expected = `<div><x-empty-namespace::button>Submit</x-empty-namespace::button></div>`;
26
+
27
+ const html = await posthtml([plugin({root: './test/templates', strict: false, namespaces: [{name: 'empty-namespace', root: './test/templates/empty-namespace'}]})]).process(actual).then(result => clean(result.html));
28
+
29
+ t.is(html, expected);
30
+ });
31
+
32
+ test('Must return node as-is when component is not found with strict mode disabled', async t => {
33
+ const actual = `<div><x-button>Submit</x-button></div>`;
34
+ const expected = `<div><x-button>Submit</x-button></div>`;
35
+
36
+ const html = await posthtml([plugin({root: './test/templates/empty-root', strict: false})]).process(actual).then(result => clean(result.html));
37
+
38
+ t.is(html, expected);
39
+ });
@@ -0,0 +1,74 @@
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 layout with locals', async t => {
9
+ const actual = `<component src="layouts/base-locals.html" locals='{ "title": "My Page" }'><div>Content</div><fill:footer>Footer</fill:footer></component>`;
10
+ const expected = `<html><head><title>My Page</title></head><body><main><div>Content</div></main><footer>Footer</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 process attributes as locals', async t => {
18
+ const actual = `<component src="components/component-locals.html" title="My Component Title" body="Content"><fill:body prepend><span>Body</span></fill:body></component>`;
19
+ const expected = `<div><h1>My Component Title</h1></div><div><span>Body</span>Content</div>`;
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
+ });
25
+
26
+ test('Must process default attributes and map attributes not locals to first node', async t => {
27
+ const actual = `<component src="components/component-mapped-attributes.html" title="My Title" class="bg-light p-2" style="display: flex; font-size: 20px"></component>`;
28
+ const expected = `<div class="text-dark m-3 bg-light p-2" style="display: flex; font-size: 20px">My Title Default body</div>`;
29
+
30
+ const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
31
+
32
+ t.is(html, expected);
33
+ });
34
+
35
+ test('Must process component with locals as JSON and string', async t => {
36
+ const actual = `<component src="components/component-locals-json-and-string.html"
37
+ merge:titles='{ "suptitle": "This is custom suptitle" }'
38
+ title="Custom title from JSON and String"
39
+ items='["another item", "yet another"]'
40
+ computed:mycomputed="true"
41
+ merge:locals='{ "items": ["first item", "second item"] }'></component>`;
42
+ const expected = `<div><div>Computed is true</div><div><h1>Custom title from JSON and String</h1></div><div><span>another item</span><span>yet another</span><span>first item</span><span>second item</span></div><div><span>title: This is default main title</span><span>subtitle: This is default subtitle</span><span>suptitle: This is custom suptitle</span></div></div>`;
43
+
44
+ const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
45
+
46
+ t.is(html, expected);
47
+ });
48
+
49
+ test('Must process parent and child locals via component', async t => {
50
+ const actual = `<x-parent aString="I am custom aString for PARENT via component (1)"><x-child></x-child></x-parent>`;
51
+ const expected = `PARENT:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>CHILD:<div> aBoolean value: true type: boolean aString value: My String Child type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>`;
52
+
53
+ const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
54
+
55
+ t.is(html, expected);
56
+ });
57
+
58
+ test('Must has access to $slots in script locals', async t => {
59
+ const actual = `<x-script-locals><fill:filled>filled slot content...</fill:filled></x-script-locals>`;
60
+ const expected = `{"filled":{"filled":true,"rendered":false,"tag":"fill:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","locals":{}}}<div>{"filled":{"filled":true,"rendered":false,"tag":"fill:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","locals":{}}}</div><div><h1>Default title</h1></div><div>filled slot content...</div>`;
61
+
62
+ const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
63
+
64
+ t.is(html, expected);
65
+ });
66
+
67
+ // test('Must pass locals from parent to child via aware', async t => {
68
+ // const actual = `<x-parent aware:aString="I am custom aString for PARENT via component (1)"><x-child></x-child></x-parent>`;
69
+ // const expected = `PARENT:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div> CHILD:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>`;
70
+ //
71
+ // const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
72
+ //
73
+ // t.is(html, expected);
74
+ // });
@@ -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 all nested component to html', async t => {
9
+ const actual = `<div><x-nested-one></x-nested-one></div>`;
10
+ const expected = `<div><div class="nested-one"><div class="nested-two"><div class="nested-three">Nested works!</div></div></div></div>`;
11
+
12
+ const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
13
+
14
+ t.is(html, expected);
15
+ });
16
+
17
+ test('Must process all nested component with slots to html', async t => {
18
+ const actual = `<x-nested-one-slot><x-nested-two-slot>yield content<fill:before2>nested-two before</fill:before2><fill:after2>nested-two after</fill:after2></x-nested-two-slot><fill:before>nested-one before</fill:before><fill:after>nested-one after</fill:after></x-nested-one-slot>`;
19
+ const expected = `<div class="nested-one"><div class="nested-one-before">nested-one before</div><div class="nested-one-yield"><div class="nested-two"><div class="nested-two-before">nested-two before</div><div class="nested-two-yield">yield content</div><div class="nested-two-after">nested-two after</div></div></div><div class="nested-one-after">nested-one after</div></div>`;
20
+
21
+ const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
22
+
23
+ t.is(html, expected);
24
+ });
@@ -0,0 +1,33 @@
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 work with posthtml-extend syntax', async t => {
9
+ // const actual = `<extends src="layouts/extend.html"><block name="content">My Content</block></extends>`;
10
+ // const expected = `<html><head><title>Extend Layout</title></head><body><main>My Content</main><footer>footer content</footer></body></html>`;
11
+ //
12
+ // const html = await posthtml([plugin({root: './test/templates', tagName: 'extends', attribute: 'src', slotTagName: 'block', fillTagName: 'block'})]).process(actual).then(result => clean(result.html));
13
+ //
14
+ // t.is(html, expected);
15
+ // });
16
+ //
17
+ // test('Must work with posthtml-modules syntax', async t => {
18
+ // const actual = `<module href="components/module.html">My Module Content</module>`;
19
+ // const expected = `<div>My Module Content</div>`;
20
+ //
21
+ // const html = await posthtml([plugin({root: './test/templates', tagName: 'module', attribute: 'href', slotTagName: 'content'})]).process(actual).then(result => clean(result.html));
22
+ //
23
+ // t.is(html, expected);
24
+ // });
25
+ //
26
+ // test('Must work with posthtml-extend and posthtml-modules syntax together', async t => {
27
+ // const actual = `<extends src="layouts/extend-with-module.html"><block name="content"><module href="components/module-with-extend.html">My Module Content</module></block></extends>`;
28
+ // const expected = `<html><head><title>Extend With Module Layout</title></head><body><main><div>My Module Content</div></main><footer>footer content</footer></body></html>`;
29
+ //
30
+ // const html = await posthtml([plugin({root: './test/templates', tagNames: ['extends', 'module'], attributes: ['src', 'href'], slotTagName: 'block', fillTagName: 'block', fallbackSlotTagName: true})]).process(actual).then(result => clean(result.html));
31
+ //
32
+ // t.is(html, expected);
33
+ // });
@@ -0,0 +1,76 @@
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 with slots', async t => {
9
+ const actual = `<component src="layouts/base.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`;
10
+ const expected = `<html><head><title>Base Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</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 process the same component multiple times', async t => {
18
+ const actual = `<component src="components/component.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component><component src="components/component.html"><fill:title>Title 2</fill:title><fill:body>Body 2</fill:body></component>`;
19
+ const expected = `<div>Title</div><div>Body</div><div>Title 2</div><div>Body 2</div>`;
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
+ });
25
+
26
+ test('Must process multiple time a slot with aware attribute', async t => {
27
+ // With aware
28
+ let actual = `<component src="components/component-multiple-slot.html"><fill:title aware>Title</fill:title><fill:body>Body</fill:body></component>`;
29
+ let expected = `<div>Title</div><div>Body</div><div>Title</div>`;
30
+
31
+ let html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
32
+
33
+ t.is(html, expected);
34
+
35
+ // Without aware
36
+ actual = `<component src="components/component-multiple-slot.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component>`;
37
+ expected = `<div>Title</div><div>Body</div><div></div>`;
38
+
39
+ html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
40
+
41
+ t.is(html, expected);
42
+ });
43
+
44
+ test('Must process append and prepend content to slot', async t => {
45
+ const actual = `<component src="components/component-append-prepend.html"><fill:title append><span>Append</span></fill:title><fill:body prepend><span>Prepend</span></fill:body></component>`;
46
+ const expected = `<div>Title<span>Append</span></div><div><span>Prepend</span>Body</div>`;
47
+
48
+ const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
49
+
50
+ t.is(html, expected);
51
+ });
52
+
53
+ test('Must process slots conditional rendering by using slot name', async t => {
54
+ let actual = `<component src="layouts/slot-condition.html"><h1>Content</h1></component>`;
55
+ let expected = `<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><p>There is not footer defined.</p></body></html>`;
56
+
57
+ let html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
58
+
59
+ t.is(html, expected);
60
+
61
+ actual = `<component src="layouts/slot-condition.html"><h1>Content</h1><fill:footer>There is now footer defined</fill:footer></component>`;
62
+ expected = `<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><footer>There is now footer defined</footer></body></html>`;
63
+
64
+ html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
65
+
66
+ t.is(html, expected);
67
+ });
68
+
69
+ test('Must render slots using $slots locals', async t => {
70
+ const actual = `<component src="layouts/base-render-slots-locals.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`;
71
+ const expected = `<html><head><title>Base Render Slots Locals Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`;
72
+
73
+ const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
74
+
75
+ t.is(html, expected);
76
+ });
@@ -0,0 +1,69 @@
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 component with x-tag', async t => {
9
+ const actual = `<x-modal></x-modal>`;
10
+ const expected = `<div>Modal</div>`;
11
+
12
+ const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
13
+
14
+ t.is(html, expected);
15
+ });
16
+
17
+ test('Must process component with namespace', async t => {
18
+ const actual = `<x-dark::button>My button</x-dark::button>`;
19
+ const expected = `<button class="bg-dark text-light">My button</button>`;
20
+
21
+ const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components'}]})]).process(actual).then(result => clean(result.html));
22
+
23
+ t.is(html, expected);
24
+ });
25
+
26
+ test('Must process component with namespace using index file', async t => {
27
+ const actual = `<x-dark::label></x-dark::label>`;
28
+ const expected = `<label class="bg-dark text-light">My Dark Label</label>`;
29
+
30
+ const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components'}]})]).process(actual).then(result => clean(result.html));
31
+
32
+ t.is(html, expected);
33
+ });
34
+
35
+ test(`Must process component with namespace's fallback path`, async t => {
36
+ const actual = `<x-dark::modal></x-dark::modal>`;
37
+ const expected = `<div>Modal</div>`;
38
+
39
+ const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', fallback: './test/templates/components'}]})]).process(actual).then(result => clean(result.html));
40
+
41
+ t.is(html, expected);
42
+ });
43
+
44
+ test(`Must process component with namespace's fallback path using index file`, async t => {
45
+ const actual = `<x-dark::form></x-dark::form>`;
46
+ const expected = `<form>My Form</form>`;
47
+
48
+ const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', fallback: './test/templates/components'}]})]).process(actual).then(result => clean(result.html));
49
+
50
+ t.is(html, expected);
51
+ });
52
+
53
+ test(`Must process component with namespace's custom path`, async t => {
54
+ const actual = `<x-dark::button>My button</x-dark::button>`;
55
+ const expected = `<button class="bg-dark-custom text-light-custom">My button</button>`;
56
+
57
+ const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', custom: './test/templates/custom/dark/components'}]})]).process(actual).then(result => clean(result.html));
58
+
59
+ t.is(html, expected);
60
+ });
61
+
62
+ test(`Must process component with namespace's custom path using index file`, async t => {
63
+ const actual = `<x-dark::label></x-dark::label>`;
64
+ const expected = `<label>My Label</label>`;
65
+
66
+ const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', custom: './test/templates/custom/dark/components'}]})]).process(actual).then(result => clean(result.html));
67
+
68
+ t.is(html, expected);
69
+ });
package/xo.config.js ADDED
@@ -0,0 +1,15 @@
1
+ module.exports = {
2
+ space: true,
3
+ rules: {
4
+ 'max-params': 0,
5
+ 'ava/no-skip-test': 0,
6
+ 'prefer-object-spread': 0,
7
+ 'capitalized-comments': 0,
8
+ 'unicorn/string-content': 0,
9
+ 'promise/prefer-await-to-then': 0,
10
+ 'unicorn/no-array-reduce': 0,
11
+ 'import/extensions': 0,
12
+ 'prefer-regex-literals': 0,
13
+ quotes: ['error', 'single', {allowTemplateLiterals: true}]
14
+ }
15
+ };