wc-compiler 0.3.1 → 0.5.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 +9 -2
- package/dist/wcc.dist.cjs +14123 -0
- package/package.json +12 -5
- package/src/wcc.js +38 -35
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wc-compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Experimental native Web Components compiler.",
|
|
5
5
|
"main": "src/wcc.js",
|
|
6
6
|
"type": "module",
|
|
@@ -10,21 +10,23 @@
|
|
|
10
10
|
"node": ">=14"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
|
-
"src/"
|
|
13
|
+
"src/",
|
|
14
|
+
"dist/wcc.dist.cjs"
|
|
14
15
|
],
|
|
15
16
|
"publishConfig": {
|
|
16
17
|
"access": "public"
|
|
17
18
|
},
|
|
18
19
|
"scripts": {
|
|
20
|
+
"clean": "rimraf ./dist",
|
|
19
21
|
"lint": "eslint \"*.*js\" \"./src/**/**/*.js\" \"./test/**/**/*.js\"",
|
|
20
22
|
"develop": "concurrently \"nodemon --watch src --watch docs -e js,md,css,html ./build.js\" \"http-server ./dist --open\"",
|
|
21
23
|
"build": "node ./build.js",
|
|
22
24
|
"serve": "node ./build.js && http-server ./dist --open",
|
|
23
|
-
"example:ssg": "node ./examples/ssg.js",
|
|
24
|
-
"example:ssr": "node ./examples/ssr.js",
|
|
25
25
|
"start": "npm run develop",
|
|
26
26
|
"test": "c8 mocha --parallel",
|
|
27
|
-
"test:tdd": "npm run test --watch"
|
|
27
|
+
"test:tdd": "npm run test --watch",
|
|
28
|
+
"dist": "rollup -c rollup.config.js",
|
|
29
|
+
"prepublishOnly": "npm run clean && npm run dist"
|
|
28
30
|
},
|
|
29
31
|
"dependencies": {
|
|
30
32
|
"acorn": "^8.7.0",
|
|
@@ -33,6 +35,8 @@
|
|
|
33
35
|
},
|
|
34
36
|
"devDependencies": {
|
|
35
37
|
"@mapbox/rehype-prism": "^0.8.0",
|
|
38
|
+
"@rollup/plugin-commonjs": "^22.0.0",
|
|
39
|
+
"@rollup/plugin-node-resolve": "^13.3.0",
|
|
36
40
|
"c8": "^7.11.2",
|
|
37
41
|
"chai": "^4.3.6",
|
|
38
42
|
"concurrently": "^7.1.0",
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
"http-server": "^14.1.0",
|
|
41
45
|
"jsdom": "^19.0.0",
|
|
42
46
|
"mocha": "^9.2.2",
|
|
47
|
+
"node-fetch": "^3.2.6",
|
|
43
48
|
"nodemon": "^2.0.15",
|
|
44
49
|
"prismjs": "^1.28.0",
|
|
45
50
|
"rehype-autolink-headings": "^6.1.1",
|
|
@@ -49,6 +54,8 @@
|
|
|
49
54
|
"remark-parse": "^10.0.1",
|
|
50
55
|
"remark-rehype": "^10.1.0",
|
|
51
56
|
"remark-toc": "^8.0.1",
|
|
57
|
+
"rimraf": "^3.0.2",
|
|
58
|
+
"rollup": "^2.75.7",
|
|
52
59
|
"simple.css": "^0.1.3",
|
|
53
60
|
"unified": "^10.1.2"
|
|
54
61
|
}
|
package/src/wcc.js
CHANGED
|
@@ -4,10 +4,7 @@ import './dom-shim.js';
|
|
|
4
4
|
import * as acorn from 'acorn';
|
|
5
5
|
import * as walk from 'acorn-walk';
|
|
6
6
|
import { parse, parseFragment, serialize } from 'parse5';
|
|
7
|
-
|
|
8
|
-
import fs from 'node:fs/promises';
|
|
9
|
-
|
|
10
|
-
let definitions;
|
|
7
|
+
import fs from 'fs';
|
|
11
8
|
|
|
12
9
|
function getParse(html) {
|
|
13
10
|
return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
|
|
@@ -23,53 +20,58 @@ function isCustomElementDefinitionNode(node) {
|
|
|
23
20
|
&& expression.callee.property.name === 'define';
|
|
24
21
|
}
|
|
25
22
|
|
|
26
|
-
async function renderComponentRoots(tree) {
|
|
23
|
+
async function renderComponentRoots(tree, definitions) {
|
|
27
24
|
for (const node of tree.childNodes) {
|
|
28
25
|
if (node.tagName && node.tagName.indexOf('-') > 0) {
|
|
29
26
|
const { tagName } = node;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
|
|
28
|
+
if (definitions[tagName]) {
|
|
29
|
+
const { moduleURL } = definitions[tagName];
|
|
30
|
+
const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
|
|
31
|
+
const elementHtml = elementInstance.shadowRoot
|
|
32
|
+
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
33
|
+
: elementInstance.innerHTML;
|
|
34
|
+
const elementTree = parseFragment(elementHtml);
|
|
35
|
+
|
|
36
|
+
node.childNodes = node.childNodes.length === 0
|
|
37
|
+
? elementTree.childNodes
|
|
38
|
+
: [...elementTree.childNodes, ...node.childNodes];
|
|
39
|
+
} else {
|
|
40
|
+
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
43
|
-
await renderComponentRoots(node);
|
|
45
|
+
await renderComponentRoots(node, definitions);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
// does this only apply to `<template>` tags?
|
|
47
49
|
if (node.content && node.content.childNodes && node.content.childNodes.length > 0) {
|
|
48
|
-
await renderComponentRoots(node.content);
|
|
50
|
+
await renderComponentRoots(node.content, definitions);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
return tree;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
const moduleContents =
|
|
57
|
+
function registerDependencies(moduleURL, definitions) {
|
|
58
|
+
const moduleContents = fs.readFileSync(moduleURL, 'utf-8');
|
|
57
59
|
|
|
58
60
|
walk.simple(acorn.parse(moduleContents, {
|
|
59
61
|
ecmaVersion: 'latest',
|
|
60
62
|
sourceType: 'module'
|
|
61
63
|
}), {
|
|
62
|
-
|
|
64
|
+
ImportDeclaration(node) {
|
|
63
65
|
const specifier = node.source.value;
|
|
64
66
|
const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
|
|
65
67
|
|
|
66
68
|
if (!isBareSpecifier) {
|
|
67
69
|
const dependencyModuleURL = new URL(node.source.value, moduleURL);
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
registerDependencies(dependencyModuleURL, definitions);
|
|
70
72
|
}
|
|
71
73
|
},
|
|
72
|
-
|
|
74
|
+
ExpressionStatement(node) {
|
|
73
75
|
if (isCustomElementDefinitionNode(node)) {
|
|
74
76
|
const { arguments: args } = node.expression;
|
|
75
77
|
const tagName = args[0].value;
|
|
@@ -84,14 +86,14 @@ async function registerDependencies(moduleURL) {
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
async function getTagName(moduleURL) {
|
|
87
|
-
const moduleContents = await fs.readFile(moduleURL, 'utf-8');
|
|
89
|
+
const moduleContents = await fs.promises.readFile(moduleURL, 'utf-8');
|
|
88
90
|
let tagName;
|
|
89
91
|
|
|
90
92
|
walk.simple(acorn.parse(moduleContents, {
|
|
91
93
|
ecmaVersion: 'latest',
|
|
92
94
|
sourceType: 'module'
|
|
93
95
|
}), {
|
|
94
|
-
|
|
96
|
+
ExpressionStatement(node) {
|
|
95
97
|
if (isCustomElementDefinitionNode(node)) {
|
|
96
98
|
|
|
97
99
|
tagName = node.expression.arguments[0].value;
|
|
@@ -102,13 +104,15 @@ async function getTagName(moduleURL) {
|
|
|
102
104
|
return tagName;
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
async function initializeCustomElement(elementURL, tagName, attrs = []) {
|
|
106
|
-
|
|
107
|
+
async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = []) {
|
|
108
|
+
registerDependencies(elementURL, definitions);
|
|
107
109
|
|
|
110
|
+
// https://github.com/ProjectEvergreen/wcc/pull/67/files#r902061804
|
|
111
|
+
const { pathname } = elementURL;
|
|
108
112
|
const element = tagName
|
|
109
113
|
? customElements.get(tagName)
|
|
110
|
-
: (await import(
|
|
111
|
-
const dataLoader = (await import(
|
|
114
|
+
: (await import(pathname)).default;
|
|
115
|
+
const dataLoader = (await import(pathname)).getData;
|
|
112
116
|
const data = dataLoader ? await dataLoader() : {};
|
|
113
117
|
const elementInstance = new element(data); // eslint-disable-line new-cap
|
|
114
118
|
|
|
@@ -126,16 +130,15 @@ async function initializeCustomElement(elementURL, tagName, attrs = []) {
|
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
async function renderToString(elementURL) {
|
|
129
|
-
definitions = [];
|
|
130
|
-
|
|
133
|
+
const definitions = [];
|
|
131
134
|
const elementTagName = await getTagName(elementURL);
|
|
132
|
-
const elementInstance = await initializeCustomElement(elementURL);
|
|
135
|
+
const elementInstance = await initializeCustomElement(elementURL, undefined, undefined, definitions);
|
|
133
136
|
|
|
134
137
|
const elementHtml = elementInstance.shadowRoot
|
|
135
138
|
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
136
139
|
: elementInstance.innerHTML;
|
|
137
140
|
const elementTree = getParse(elementHtml)(elementHtml);
|
|
138
|
-
const finalTree = await renderComponentRoots(elementTree);
|
|
141
|
+
const finalTree = await renderComponentRoots(elementTree, definitions);
|
|
139
142
|
const html = elementTagName ? `
|
|
140
143
|
<${elementTagName}>
|
|
141
144
|
${serialize(finalTree)}
|
|
@@ -150,14 +153,14 @@ async function renderToString(elementURL) {
|
|
|
150
153
|
}
|
|
151
154
|
|
|
152
155
|
async function renderFromHTML(html, elements = []) {
|
|
153
|
-
definitions = [];
|
|
156
|
+
const definitions = [];
|
|
154
157
|
|
|
155
158
|
for (const url of elements) {
|
|
156
|
-
await initializeCustomElement(url);
|
|
159
|
+
await initializeCustomElement(url, undefined, undefined, definitions);
|
|
157
160
|
}
|
|
158
161
|
|
|
159
162
|
const elementTree = getParse(html)(html);
|
|
160
|
-
const finalTree = await renderComponentRoots(elementTree);
|
|
163
|
+
const finalTree = await renderComponentRoots(elementTree, definitions);
|
|
161
164
|
|
|
162
165
|
return {
|
|
163
166
|
html: serialize(finalTree),
|