wc-compiler 0.14.0 → 0.15.0

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.
package/dist/wcc.dist.cjs CHANGED
@@ -34004,6 +34004,24 @@ function parseJsx(moduleURL) {
34004
34004
  /* eslint-disable max-depth */
34005
34005
  // this must come first
34006
34006
 
34007
+ // https://developer.mozilla.org/en-US/docs/Glossary/Void_element
34008
+ const VOID_ELEMENTS = [
34009
+ 'area',
34010
+ 'base',
34011
+ 'br',
34012
+ 'col',
34013
+ 'embed',
34014
+ 'hr',
34015
+ 'img',
34016
+ 'input',
34017
+ 'link',
34018
+ 'meta',
34019
+ 'param', // deprecated
34020
+ 'source',
34021
+ 'track',
34022
+ 'wbr'
34023
+ ];
34024
+
34007
34025
  function getParse(html) {
34008
34026
  return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
34009
34027
  ? parse$1
@@ -34025,17 +34043,26 @@ async function renderComponentRoots(tree, definitions) {
34025
34043
 
34026
34044
  if (definitions[tagName]) {
34027
34045
  const { moduleURL } = definitions[tagName];
34028
- const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
34029
- const elementHtml = elementInstance.shadowRoot
34030
- ? elementInstance.getInnerHTML({ includeShadowRoots: true })
34031
- : elementInstance.innerHTML;
34032
- const elementTree = parseFragment(elementHtml);
34033
-
34034
- node.childNodes = node.childNodes.length === 0
34035
- ? elementTree.childNodes
34036
- : [...elementTree.childNodes, ...node.childNodes];
34046
+ const elementInstance = await initializeCustomElement(moduleURL, tagName, node, definitions);
34047
+
34048
+ if (elementInstance) {
34049
+ const hasShadow = elementInstance.shadowRoot;
34050
+ const elementHtml = hasShadow
34051
+ ? elementInstance.getInnerHTML({ includeShadowRoots: true })
34052
+ : elementInstance.innerHTML;
34053
+ const elementTree = parseFragment(elementHtml);
34054
+ const hasLight = elementTree.childNodes > 0;
34055
+
34056
+ node.childNodes = node.childNodes.length === 0 && hasLight && !hasShadow
34057
+ ? elementTree.childNodes
34058
+ : hasShadow
34059
+ ? [...elementTree.childNodes, ...node.childNodes]
34060
+ : elementTree.childNodes;
34061
+ } else {
34062
+ console.warn(`WARNING: customElement <${tagName}> detected but not serialized. You may not have exported it.`);
34063
+ }
34037
34064
  } else {
34038
- console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
34065
+ console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it.`);
34039
34066
  }
34040
34067
  }
34041
34068
 
@@ -34074,7 +34101,7 @@ function registerDependencies(moduleURL, definitions, depth = 0) {
34074
34101
  const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
34075
34102
  const extension = specifier.split('.').pop();
34076
34103
 
34077
- // TODO would like to decouple .jsx from the core, ideally
34104
+ // would like to decouple .jsx from the core, ideally
34078
34105
  // https://github.com/ProjectEvergreen/wcc/issues/122
34079
34106
  if (!isBareSpecifier && ['js', 'jsx', 'ts'].includes(extension)) {
34080
34107
  const dependencyModuleURL = new URL(node.source.value, moduleURL);
@@ -34130,7 +34157,41 @@ async function getTagName(moduleURL) {
34130
34157
  return tagName;
34131
34158
  }
34132
34159
 
34133
- async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = [], isEntry, props = {}) {
34160
+ function renderLightDomChildren(childNodes, iHTML = '') {
34161
+ let innerHTML = iHTML;
34162
+
34163
+ childNodes.forEach((child) => {
34164
+ const { nodeName, attrs = [], value } = child;
34165
+
34166
+ if (nodeName !== '#text') {
34167
+ innerHTML += `<${nodeName}`;
34168
+
34169
+ if (attrs.length > 0) {
34170
+ attrs.forEach(attr => {
34171
+ innerHTML += ` ${attr.name}="${attr.value}"`;
34172
+ });
34173
+ }
34174
+
34175
+ innerHTML += '>';
34176
+
34177
+ if (child.childNodes.length > 0) {
34178
+ innerHTML = renderLightDomChildren(child.childNodes, innerHTML);
34179
+ }
34180
+
34181
+ innerHTML += VOID_ELEMENTS.includes(nodeName)
34182
+ ? ''
34183
+ : `</${nodeName}>`;
34184
+ } else if (nodeName === '#text') {
34185
+ innerHTML += value;
34186
+ }
34187
+ });
34188
+
34189
+ return innerHTML;
34190
+ }
34191
+
34192
+ async function initializeCustomElement(elementURL, tagName, node = {}, definitions = [], isEntry, props = {}) {
34193
+ const { attrs = [], childNodes = [] } = node;
34194
+
34134
34195
  if (!tagName) {
34135
34196
  const depth = isEntry ? 1 : 0;
34136
34197
  registerDependencies(elementURL, definitions, depth);
@@ -34150,6 +34211,9 @@ async function initializeCustomElement(elementURL, tagName, attrs = [], definiti
34150
34211
  if (element) {
34151
34212
  const elementInstance = new element(data); // eslint-disable-line new-cap
34152
34213
 
34214
+ // support for HTML (Light DOM) Web Components
34215
+ elementInstance.innerHTML = renderLightDomChildren(childNodes);
34216
+
34153
34217
  attrs.forEach((attr) => {
34154
34218
  elementInstance.setAttribute(attr.name, attr.value);
34155
34219
 
@@ -34199,7 +34263,7 @@ async function renderFromHTML(html, elements = []) {
34199
34263
  const definitions = [];
34200
34264
 
34201
34265
  for (const url of elements) {
34202
- await initializeCustomElement(url, undefined, undefined, definitions, true);
34266
+ registerDependencies(url, definitions, 1);
34203
34267
  }
34204
34268
 
34205
34269
  const elementTree = getParse(html)(html);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wc-compiler",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Experimental native Web Components compiler.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/wcc.js CHANGED
@@ -12,6 +12,24 @@ import { importAttributes } from 'acorn-import-attributes';
12
12
  import { transform } from 'sucrase';
13
13
  import fs from 'fs';
14
14
 
15
+ // https://developer.mozilla.org/en-US/docs/Glossary/Void_element
16
+ const VOID_ELEMENTS = [
17
+ 'area',
18
+ 'base',
19
+ 'br',
20
+ 'col',
21
+ 'embed',
22
+ 'hr',
23
+ 'img',
24
+ 'input',
25
+ 'link',
26
+ 'meta',
27
+ 'param', // deprecated
28
+ 'source',
29
+ 'track',
30
+ 'wbr'
31
+ ];
32
+
15
33
  function getParse(html) {
16
34
  return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
17
35
  ? parse
@@ -33,17 +51,26 @@ async function renderComponentRoots(tree, definitions) {
33
51
 
34
52
  if (definitions[tagName]) {
35
53
  const { moduleURL } = definitions[tagName];
36
- const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
37
- const elementHtml = elementInstance.shadowRoot
38
- ? elementInstance.getInnerHTML({ includeShadowRoots: true })
39
- : elementInstance.innerHTML;
40
- const elementTree = parseFragment(elementHtml);
41
-
42
- node.childNodes = node.childNodes.length === 0
43
- ? elementTree.childNodes
44
- : [...elementTree.childNodes, ...node.childNodes];
54
+ const elementInstance = await initializeCustomElement(moduleURL, tagName, node, definitions);
55
+
56
+ if (elementInstance) {
57
+ const hasShadow = elementInstance.shadowRoot;
58
+ const elementHtml = hasShadow
59
+ ? elementInstance.getInnerHTML({ includeShadowRoots: true })
60
+ : elementInstance.innerHTML;
61
+ const elementTree = parseFragment(elementHtml);
62
+ const hasLight = elementTree.childNodes > 0;
63
+
64
+ node.childNodes = node.childNodes.length === 0 && hasLight && !hasShadow
65
+ ? elementTree.childNodes
66
+ : hasShadow
67
+ ? [...elementTree.childNodes, ...node.childNodes]
68
+ : elementTree.childNodes;
69
+ } else {
70
+ console.warn(`WARNING: customElement <${tagName}> detected but not serialized. You may not have exported it.`);
71
+ }
45
72
  } else {
46
- console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
73
+ console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it.`);
47
74
  }
48
75
  }
49
76
 
@@ -82,7 +109,7 @@ function registerDependencies(moduleURL, definitions, depth = 0) {
82
109
  const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
83
110
  const extension = specifier.split('.').pop();
84
111
 
85
- // TODO would like to decouple .jsx from the core, ideally
112
+ // would like to decouple .jsx from the core, ideally
86
113
  // https://github.com/ProjectEvergreen/wcc/issues/122
87
114
  if (!isBareSpecifier && ['js', 'jsx', 'ts'].includes(extension)) {
88
115
  const dependencyModuleURL = new URL(node.source.value, moduleURL);
@@ -138,7 +165,41 @@ async function getTagName(moduleURL) {
138
165
  return tagName;
139
166
  }
140
167
 
141
- async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = [], isEntry, props = {}) {
168
+ function renderLightDomChildren(childNodes, iHTML = '') {
169
+ let innerHTML = iHTML;
170
+
171
+ childNodes.forEach((child) => {
172
+ const { nodeName, attrs = [], value } = child;
173
+
174
+ if (nodeName !== '#text') {
175
+ innerHTML += `<${nodeName}`;
176
+
177
+ if (attrs.length > 0) {
178
+ attrs.forEach(attr => {
179
+ innerHTML += ` ${attr.name}="${attr.value}"`;
180
+ });
181
+ }
182
+
183
+ innerHTML += '>';
184
+
185
+ if (child.childNodes.length > 0) {
186
+ innerHTML = renderLightDomChildren(child.childNodes, innerHTML);
187
+ }
188
+
189
+ innerHTML += VOID_ELEMENTS.includes(nodeName)
190
+ ? ''
191
+ : `</${nodeName}>`;
192
+ } else if (nodeName === '#text') {
193
+ innerHTML += value;
194
+ }
195
+ });
196
+
197
+ return innerHTML;
198
+ }
199
+
200
+ async function initializeCustomElement(elementURL, tagName, node = {}, definitions = [], isEntry, props = {}) {
201
+ const { attrs = [], childNodes = [] } = node;
202
+
142
203
  if (!tagName) {
143
204
  const depth = isEntry ? 1 : 0;
144
205
  registerDependencies(elementURL, definitions, depth);
@@ -158,6 +219,9 @@ async function initializeCustomElement(elementURL, tagName, attrs = [], definiti
158
219
  if (element) {
159
220
  const elementInstance = new element(data); // eslint-disable-line new-cap
160
221
 
222
+ // support for HTML (Light DOM) Web Components
223
+ elementInstance.innerHTML = renderLightDomChildren(childNodes);
224
+
161
225
  attrs.forEach((attr) => {
162
226
  elementInstance.setAttribute(attr.name, attr.value);
163
227
 
@@ -207,7 +271,7 @@ async function renderFromHTML(html, elements = []) {
207
271
  const definitions = [];
208
272
 
209
273
  for (const url of elements) {
210
- await initializeCustomElement(url, undefined, undefined, definitions, true);
274
+ registerDependencies(url, definitions, 1);
211
275
  }
212
276
 
213
277
  const elementTree = getParse(html)(html);