wc-compiler 0.15.1 → 0.17.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/README.md +2 -8
- package/package.json +27 -20
- package/src/dom-shim.js +168 -34
- package/src/index.d.ts +19 -0
- package/src/jsx-loader.js +15 -7
- package/src/register.js +3 -0
- package/src/wcc.js +60 -112
- package/dist/wcc.dist.cjs +0 -32381
- package/src/ts-loader.js +0 -32
package/src/wcc.js
CHANGED
|
@@ -1,39 +1,14 @@
|
|
|
1
|
-
/* eslint-disable max-depth */
|
|
2
1
|
// this must come first
|
|
3
|
-
import './dom-shim.js';
|
|
2
|
+
import { getParse } from './dom-shim.js';
|
|
4
3
|
|
|
5
4
|
import * as acorn from 'acorn';
|
|
6
5
|
import * as walk from 'acorn-walk';
|
|
7
6
|
import { generate } from 'astring';
|
|
8
7
|
import { getParser, parseJsx } from './jsx-loader.js';
|
|
9
|
-
import {
|
|
8
|
+
import { serialize } from 'parse5';
|
|
10
9
|
import { transform } from 'sucrase';
|
|
11
10
|
import fs from 'fs';
|
|
12
11
|
|
|
13
|
-
// https://developer.mozilla.org/en-US/docs/Glossary/Void_element
|
|
14
|
-
const VOID_ELEMENTS = [
|
|
15
|
-
'area',
|
|
16
|
-
'base',
|
|
17
|
-
'br',
|
|
18
|
-
'col',
|
|
19
|
-
'embed',
|
|
20
|
-
'hr',
|
|
21
|
-
'img',
|
|
22
|
-
'input',
|
|
23
|
-
'link',
|
|
24
|
-
'meta',
|
|
25
|
-
'param', // deprecated
|
|
26
|
-
'source',
|
|
27
|
-
'track',
|
|
28
|
-
'wbr'
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
function getParse(html) {
|
|
32
|
-
return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
|
|
33
|
-
? parse
|
|
34
|
-
: parseFragment;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
12
|
function isCustomElementDefinitionNode(node) {
|
|
38
13
|
const { expression } = node;
|
|
39
14
|
|
|
@@ -45,7 +20,7 @@ function isCustomElementDefinitionNode(node) {
|
|
|
45
20
|
async function renderComponentRoots(tree, definitions) {
|
|
46
21
|
for (const node of tree.childNodes) {
|
|
47
22
|
if (node.tagName && node.tagName.indexOf('-') > 0) {
|
|
48
|
-
const { tagName } = node;
|
|
23
|
+
const { attrs, tagName } = node;
|
|
49
24
|
|
|
50
25
|
if (definitions[tagName]) {
|
|
51
26
|
const { moduleURL } = definitions[tagName];
|
|
@@ -53,31 +28,35 @@ async function renderComponentRoots(tree, definitions) {
|
|
|
53
28
|
|
|
54
29
|
if (elementInstance) {
|
|
55
30
|
const hasShadow = elementInstance.shadowRoot;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const hasLight = elementTree.childNodes > 0;
|
|
61
|
-
|
|
62
|
-
node.childNodes = node.childNodes.length === 0 && hasLight && !hasShadow
|
|
63
|
-
? elementTree.childNodes
|
|
64
|
-
: hasShadow
|
|
65
|
-
? [...elementTree.childNodes, ...node.childNodes]
|
|
66
|
-
: elementTree.childNodes;
|
|
31
|
+
|
|
32
|
+
node.childNodes = hasShadow
|
|
33
|
+
? [...elementInstance.shadowRoot.childNodes, ...node.childNodes]
|
|
34
|
+
: elementInstance.childNodes;
|
|
67
35
|
} else {
|
|
68
36
|
console.warn(`WARNING: customElement <${tagName}> detected but not serialized. You may not have exported it.`);
|
|
69
37
|
}
|
|
70
38
|
} else {
|
|
71
39
|
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it.`);
|
|
72
40
|
}
|
|
41
|
+
|
|
42
|
+
attrs.forEach((attr) => {
|
|
43
|
+
if (attr.name === 'hydrate') {
|
|
44
|
+
definitions[tagName].hydrate = attr.value;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
73
48
|
}
|
|
74
49
|
|
|
75
50
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
76
51
|
await renderComponentRoots(node, definitions);
|
|
77
52
|
}
|
|
78
53
|
|
|
54
|
+
if (node.shadowRoot && node.shadowRoot.childNodes?.length > 0) {
|
|
55
|
+
await renderComponentRoots(node.shadowRoot, definitions);
|
|
56
|
+
}
|
|
57
|
+
|
|
79
58
|
// does this only apply to `<template>` tags?
|
|
80
|
-
if (node.content && node.content.childNodes
|
|
59
|
+
if (node.content && node.content.childNodes?.length > 0) {
|
|
81
60
|
await renderComponentRoots(node.content, definitions);
|
|
82
61
|
}
|
|
83
62
|
}
|
|
@@ -104,19 +83,23 @@ function registerDependencies(moduleURL, definitions, depth = 0) {
|
|
|
104
83
|
}), {
|
|
105
84
|
ImportDeclaration(node) {
|
|
106
85
|
const specifier = node.source.value;
|
|
107
|
-
const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
|
|
108
|
-
const extension = specifier.split('.').pop();
|
|
109
86
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
87
|
+
if (typeof specifier === 'string') {
|
|
88
|
+
const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
|
|
89
|
+
const extension = typeof specifier === "string" ? specifier.split('.').pop() : "";
|
|
90
|
+
|
|
91
|
+
// would like to decouple .jsx from the core, ideally
|
|
92
|
+
// https://github.com/ProjectEvergreen/wcc/issues/122
|
|
93
|
+
if (!isBareSpecifier && ['js', 'jsx', 'ts'].includes(extension)) {
|
|
94
|
+
const dependencyModuleURL = new URL(specifier, moduleURL);
|
|
114
95
|
|
|
115
|
-
|
|
96
|
+
registerDependencies(dependencyModuleURL, definitions, nextDepth);
|
|
97
|
+
}
|
|
116
98
|
}
|
|
117
99
|
},
|
|
118
100
|
ExpressionStatement(node) {
|
|
119
101
|
if (isCustomElementDefinitionNode(node)) {
|
|
102
|
+
// @ts-ignore
|
|
120
103
|
const { arguments: args } = node.expression;
|
|
121
104
|
const tagName = args[0].type === 'Literal'
|
|
122
105
|
? args[0].value // single and double quotes
|
|
@@ -155,6 +138,7 @@ async function getTagName(moduleURL) {
|
|
|
155
138
|
}), {
|
|
156
139
|
ExpressionStatement(node) {
|
|
157
140
|
if (isCustomElementDefinitionNode(node)) {
|
|
141
|
+
// @ts-ignore
|
|
158
142
|
tagName = node.expression.arguments[0].value;
|
|
159
143
|
}
|
|
160
144
|
}
|
|
@@ -163,98 +147,60 @@ async function getTagName(moduleURL) {
|
|
|
163
147
|
return tagName;
|
|
164
148
|
}
|
|
165
149
|
|
|
166
|
-
function
|
|
167
|
-
let innerHTML = iHTML;
|
|
168
|
-
|
|
169
|
-
childNodes.forEach((child) => {
|
|
170
|
-
const { nodeName, attrs = [], value } = child;
|
|
171
|
-
|
|
172
|
-
if (nodeName !== '#text') {
|
|
173
|
-
innerHTML += `<${nodeName}`;
|
|
174
|
-
|
|
175
|
-
if (attrs.length > 0) {
|
|
176
|
-
attrs.forEach(attr => {
|
|
177
|
-
innerHTML += ` ${attr.name}="${attr.value}"`;
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
innerHTML += '>';
|
|
182
|
-
|
|
183
|
-
if (child.childNodes.length > 0) {
|
|
184
|
-
innerHTML = renderLightDomChildren(child.childNodes, innerHTML);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
innerHTML += VOID_ELEMENTS.includes(nodeName)
|
|
188
|
-
? ''
|
|
189
|
-
: `</${nodeName}>`;
|
|
190
|
-
} else if (nodeName === '#text') {
|
|
191
|
-
innerHTML += value;
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
return innerHTML;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async function initializeCustomElement(elementURL, tagName, node = {}, definitions = [], isEntry, props = {}) {
|
|
199
|
-
const { attrs = [], childNodes = [] } = node;
|
|
150
|
+
async function initializeCustomElement(elementURL, tagName, node = {}, definitions = {}, isEntry, props = {}) {
|
|
200
151
|
|
|
201
152
|
if (!tagName) {
|
|
202
153
|
const depth = isEntry ? 1 : 0;
|
|
203
154
|
registerDependencies(elementURL, definitions, depth);
|
|
204
155
|
}
|
|
205
156
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
const element = customElements.get(tagName) ?? (await import(href)).default;
|
|
210
|
-
const dataLoader = (await import(href)).getData;
|
|
211
|
-
const data = props
|
|
212
|
-
? props
|
|
213
|
-
: dataLoader
|
|
214
|
-
? await dataLoader(props)
|
|
215
|
-
: {};
|
|
157
|
+
const element = customElements.get(tagName) ?? (await import(elementURL)).default;
|
|
158
|
+
const dataLoader = (await import(elementURL)).getData;
|
|
159
|
+
const data = props ? props : dataLoader ? await dataLoader(props) : {};
|
|
216
160
|
|
|
217
161
|
if (element) {
|
|
218
|
-
const elementInstance = new element(data);
|
|
162
|
+
const elementInstance = new element(data);
|
|
219
163
|
|
|
220
|
-
|
|
221
|
-
elementInstance.innerHTML = renderLightDomChildren(childNodes);
|
|
164
|
+
Object.assign(elementInstance, node);
|
|
222
165
|
|
|
223
|
-
attrs.forEach((attr) => {
|
|
224
|
-
elementInstance.setAttribute(attr.name, attr.value);
|
|
225
|
-
|
|
226
|
-
if (attr.name === 'hydrate') {
|
|
227
|
-
definitions[tagName].hydrate = attr.value;
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
|
|
231
166
|
await elementInstance.connectedCallback();
|
|
232
|
-
|
|
167
|
+
|
|
233
168
|
return elementInstance;
|
|
234
169
|
}
|
|
235
170
|
}
|
|
236
171
|
|
|
172
|
+
/** @type {import('./index.d.ts').renderToString} */
|
|
237
173
|
async function renderToString(elementURL, wrappingEntryTag = true, props = {}) {
|
|
238
|
-
|
|
174
|
+
/** @type {import('./index.d.ts').Metadata} */
|
|
175
|
+
const definitions = {};
|
|
239
176
|
const elementTagName = wrappingEntryTag && await getTagName(elementURL);
|
|
240
177
|
const isEntry = !!elementTagName;
|
|
241
178
|
const elementInstance = await initializeCustomElement(elementURL, undefined, undefined, definitions, isEntry, props);
|
|
179
|
+
|
|
242
180
|
let html;
|
|
243
181
|
|
|
244
182
|
// in case the entry point isn't valid
|
|
245
183
|
if (elementInstance) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
184
|
+
elementInstance.nodeName = elementTagName ?? '';
|
|
185
|
+
elementInstance.tagName = elementTagName ?? '';
|
|
186
|
+
|
|
187
|
+
await renderComponentRoots(
|
|
188
|
+
elementInstance.shadowRoot
|
|
189
|
+
?
|
|
190
|
+
{
|
|
191
|
+
nodeName: '#document-fragment',
|
|
192
|
+
childNodes: [elementInstance]
|
|
193
|
+
}
|
|
194
|
+
: elementInstance,
|
|
195
|
+
definitions
|
|
196
|
+
);
|
|
251
197
|
|
|
252
198
|
html = wrappingEntryTag && elementTagName ? `
|
|
253
199
|
<${elementTagName}>
|
|
254
|
-
${serialize(
|
|
200
|
+
${serialize(elementInstance)}
|
|
255
201
|
</${elementTagName}>
|
|
256
202
|
`
|
|
257
|
-
: serialize(
|
|
203
|
+
: serialize(elementInstance);
|
|
258
204
|
} else {
|
|
259
205
|
console.warn('WARNING: No custom element class found for this entry point.');
|
|
260
206
|
}
|
|
@@ -265,8 +211,10 @@ async function renderToString(elementURL, wrappingEntryTag = true, props = {}) {
|
|
|
265
211
|
};
|
|
266
212
|
}
|
|
267
213
|
|
|
214
|
+
/** @type {import('./index.d.ts').renderFromHTML} */
|
|
268
215
|
async function renderFromHTML(html, elements = []) {
|
|
269
|
-
|
|
216
|
+
/** @type {import('./index.d.ts').Metadata} */
|
|
217
|
+
const definitions = {};
|
|
270
218
|
|
|
271
219
|
for (const url of elements) {
|
|
272
220
|
registerDependencies(url, definitions, 1);
|