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/README.md
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://app.netlify.com/sites/merry-caramel-524e61/deploys)
|
|
6
6
|
[](https://github.com/ProjectEvergreen/wcc/tags)
|
|
7
|
-

|
|
8
7
|
[](https://raw.githubusercontent.com/ProjectEvergreen/wcc/master/LICENSE.md)
|
|
8
|
+
[](https://nodejs.org/en/about/previous-releases")
|
|
9
|
+
[](https://www.greenwoodjs.dev/discord/)
|
|
9
10
|
|
|
10
11
|
> _Experimental Web Components compiler. It's Web Components all the way down!_ 🐢
|
|
11
12
|
|
|
@@ -73,13 +74,6 @@
|
|
|
73
74
|
$ npm install wc-compiler --save-dev
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
### CommonJS
|
|
77
|
-
|
|
78
|
-
If you need CommonJS support, a separate pre-bundled (with Rollup) distribution of **WCC** is available at _dist/wcc.dist.cjs_. Example:
|
|
79
|
-
```js
|
|
80
|
-
const { renderToString } = require('wc-compiler/dist/wcc.dist.cjs');
|
|
81
|
-
```
|
|
82
|
-
|
|
83
77
|
## Documentation
|
|
84
78
|
|
|
85
79
|
See our [website](https://merry-caramel-524e61.netlify.app/) for API docs and examples.
|
package/package.json
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wc-compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Experimental native Web Components compiler.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/ProjectEvergreen/wcc.git"
|
|
8
8
|
},
|
|
9
|
-
"main": "src/wcc.js",
|
|
10
9
|
"type": "module",
|
|
10
|
+
"main": "src/wcc.js",
|
|
11
|
+
"types": "./src/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./src/wcc.js",
|
|
15
|
+
"types": "./src/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./register": "./src/register.js",
|
|
18
|
+
"./src/jsx-loader.js": "./src/jsx-loader.js"
|
|
19
|
+
},
|
|
11
20
|
"author": "Owen Buckley <owen@thegreenhouse.io>",
|
|
12
21
|
"keywords": [
|
|
13
22
|
"Web Components",
|
|
@@ -17,53 +26,51 @@
|
|
|
17
26
|
],
|
|
18
27
|
"license": "MIT",
|
|
19
28
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
29
|
+
"node": ">=18"
|
|
21
30
|
},
|
|
22
31
|
"files": [
|
|
23
|
-
"src/"
|
|
24
|
-
"dist/wcc.dist.cjs"
|
|
32
|
+
"src/"
|
|
25
33
|
],
|
|
26
34
|
"publishConfig": {
|
|
27
35
|
"access": "public"
|
|
28
36
|
},
|
|
29
37
|
"scripts": {
|
|
30
38
|
"clean": "rimraf ./dist",
|
|
31
|
-
"lint": "eslint
|
|
39
|
+
"lint": "eslint",
|
|
40
|
+
"lint:types": "tsc --project tsconfig.json",
|
|
32
41
|
"docs:dev": "concurrently \"nodemon --watch src --watch docs -e js,md,css,html,jsx ./build.js\" \"http-server ./dist --open\"",
|
|
33
42
|
"docs:build": "node ./build.js",
|
|
34
43
|
"docs:serve": "npm run clean && npm run docs:build && http-server ./dist --open",
|
|
35
|
-
"sandbox": "npm run clean && concurrently \"nodemon --loader ./test-
|
|
44
|
+
"sandbox": "npm run clean && concurrently \"nodemon --loader ./test-loader.js --watch src --watch sandbox -e js,md,css,html,jsx,ts ./sandbox.js\" \"http-server ./dist --open\" \"livereload ./dist\"",
|
|
36
45
|
"start": "npm run docs:serve",
|
|
37
46
|
"test": "mocha --exclude \"./test/cases/jsx*/**\" --exclude \"./test/cases/ts*/**\" --exclude \"./test/cases/custom-extension/**\" \"./test/**/**/*.spec.js\"",
|
|
38
|
-
"test:
|
|
47
|
+
"test:jsx": "c8 node --import ./test-register.js --experimental-strip-types ./node_modules/mocha/bin/mocha \"./test/**/**/*.spec.js\"",
|
|
39
48
|
"test:tdd": "npm run test -- --watch",
|
|
40
|
-
"test:tdd:
|
|
41
|
-
"dist": "rollup -c rollup.config.js",
|
|
42
|
-
"prepublishOnly": "npm run clean && npm run dist"
|
|
49
|
+
"test:tdd:jsx": "npm run test:jsx -- --watch"
|
|
43
50
|
},
|
|
44
51
|
"dependencies": {
|
|
45
52
|
"@projectevergreen/acorn-jsx-esm": "~0.1.0",
|
|
46
53
|
"acorn": "^8.14.0",
|
|
47
54
|
"acorn-walk": "^8.3.4",
|
|
48
55
|
"astring": "^1.9.0",
|
|
49
|
-
"parse5": "^
|
|
56
|
+
"parse5": "^7.2.1",
|
|
50
57
|
"sucrase": "^3.35.0"
|
|
51
58
|
},
|
|
52
59
|
"devDependencies": {
|
|
53
60
|
"@babel/core": "^7.24.4",
|
|
54
|
-
"@babel/eslint-parser": "^7.
|
|
55
|
-
"@babel/plugin-syntax-import-assertions": "^7.
|
|
56
|
-
"@
|
|
61
|
+
"@babel/eslint-parser": "^7.25.7",
|
|
62
|
+
"@babel/plugin-syntax-import-assertions": "^7.25.7",
|
|
63
|
+
"@eslint/js": "^9.11.1",
|
|
57
64
|
"@ls-lint/ls-lint": "^1.10.0",
|
|
58
65
|
"@mapbox/rehype-prism": "^0.8.0",
|
|
59
|
-
"@
|
|
60
|
-
"@
|
|
66
|
+
"@types/mocha": "^10.0.10",
|
|
67
|
+
"@types/node": "^22.13.4",
|
|
61
68
|
"c8": "^7.11.2",
|
|
62
69
|
"chai": "^4.3.6",
|
|
63
70
|
"concurrently": "^7.1.0",
|
|
64
|
-
"eslint": "^
|
|
65
|
-
"eslint-plugin-markdown": "^3.0.0",
|
|
71
|
+
"eslint": "^9.11.1",
|
|
66
72
|
"eslint-plugin-no-only-tests": "^2.6.0",
|
|
73
|
+
"globals": "^15.10.0",
|
|
67
74
|
"http-server": "^14.1.0",
|
|
68
75
|
"jsdom": "^19.0.0",
|
|
69
76
|
"livereload": "^0.9.3",
|
|
@@ -78,8 +85,8 @@
|
|
|
78
85
|
"remark-rehype": "^10.1.0",
|
|
79
86
|
"remark-toc": "^8.0.1",
|
|
80
87
|
"rimraf": "^3.0.2",
|
|
81
|
-
"rollup": "^4.26.0",
|
|
82
88
|
"simple.css": "^0.1.3",
|
|
89
|
+
"typescript": "^5.8.2",
|
|
83
90
|
"unified": "^10.1.2"
|
|
84
91
|
}
|
|
85
92
|
}
|
package/src/dom-shim.js
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { parse, parseFragment, serialize } from 'parse5';
|
|
3
|
+
|
|
4
|
+
export function getParse(html) {
|
|
5
|
+
return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
|
|
6
|
+
? parse
|
|
7
|
+
: parseFragment;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isShadowRoot(element) {
|
|
11
|
+
return Object.getPrototypeOf(element).constructor.name === 'ShadowRoot';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function deepClone(obj, map = new WeakMap()) {
|
|
15
|
+
if (obj === null || typeof obj !== 'object') {
|
|
16
|
+
return obj;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof obj === 'function') {
|
|
20
|
+
const clonedFn = obj.bind({});
|
|
21
|
+
Object.assign(clonedFn, obj);
|
|
22
|
+
return clonedFn;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (map.has(obj)) {
|
|
26
|
+
return map.get(obj);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = Array.isArray(obj) ? [] : {};
|
|
30
|
+
map.set(obj, result);
|
|
31
|
+
|
|
32
|
+
for (const key of Object.keys(obj)) {
|
|
33
|
+
result[key] = deepClone(obj[key], map);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Creates an empty parse5 element without the parse5 overhead resulting in better performance
|
|
40
|
+
function getParse5ElementDefaults(element, tagName) {
|
|
41
|
+
return {
|
|
42
|
+
addEventListener: noop,
|
|
43
|
+
attrs: [],
|
|
44
|
+
parentNode: element.parentNode,
|
|
45
|
+
childNodes: [],
|
|
46
|
+
nodeName: tagName,
|
|
47
|
+
tagName: tagName,
|
|
48
|
+
namespaceURI: 'http://www.w3.org/1999/xhtml',
|
|
49
|
+
...(tagName === 'template' ? { content: { nodeName: '#document-fragment', childNodes: [] } } : {})
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
1
53
|
function noop() { }
|
|
2
54
|
|
|
3
55
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet
|
|
@@ -19,13 +71,81 @@ class EventTarget {
|
|
|
19
71
|
// EventTarget <- Node
|
|
20
72
|
// TODO should be an interface?
|
|
21
73
|
class Node extends EventTarget {
|
|
22
|
-
|
|
74
|
+
constructor() {
|
|
75
|
+
super();
|
|
76
|
+
// Parse5 properties
|
|
77
|
+
this.attrs = [];
|
|
78
|
+
this.parentNode = null;
|
|
79
|
+
this.childNodes = [];
|
|
80
|
+
this.nodeName = '';
|
|
81
|
+
}
|
|
82
|
+
|
|
23
83
|
cloneNode(deep) {
|
|
24
|
-
return this;
|
|
84
|
+
return deep ? deepClone(this) : Object.assign({}, this);
|
|
25
85
|
}
|
|
26
86
|
|
|
27
87
|
appendChild(node) {
|
|
28
|
-
|
|
88
|
+
const childNodes = (this.nodeName === 'template' ? this.content : this).childNodes;
|
|
89
|
+
|
|
90
|
+
if (node.parentNode) {
|
|
91
|
+
node.parentNode?.removeChild?.(node);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (node.nodeName === 'template') {
|
|
95
|
+
if (isShadowRoot(this) && this.mode) {
|
|
96
|
+
node.attrs = [{ name: 'shadowrootmode', value: this.mode }];
|
|
97
|
+
childNodes.push(node);
|
|
98
|
+
node.parentNode = this;
|
|
99
|
+
} else {
|
|
100
|
+
this.childNodes = [...this.childNodes, ...node.content.childNodes];
|
|
101
|
+
}
|
|
102
|
+
} else if (node instanceof DocumentFragment) {
|
|
103
|
+
this.childNodes = [...this.childNodes, ...node.childNodes];
|
|
104
|
+
} else {
|
|
105
|
+
childNodes.push(node);
|
|
106
|
+
node.parentNode = this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return node;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
removeChild(node) {
|
|
113
|
+
const childNodes = (this.nodeName === 'template' ? this.content : this).childNodes;
|
|
114
|
+
if (!childNodes || !childNodes.length) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const index = childNodes.indexOf(node);
|
|
119
|
+
if (index === -1) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
childNodes.splice(index, 1);
|
|
124
|
+
node.parentNode = null;
|
|
125
|
+
|
|
126
|
+
return node;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get textContent() {
|
|
130
|
+
if (this.nodeName === '#text') {
|
|
131
|
+
return this.value || '';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return this.childNodes
|
|
135
|
+
.map((child) => child.nodeName === '#text' ? child.value : child.textContent)
|
|
136
|
+
.join('');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
set textContent(value) {
|
|
140
|
+
this.childNodes = [];
|
|
141
|
+
|
|
142
|
+
if (value) {
|
|
143
|
+
const textNode = new Node();
|
|
144
|
+
textNode.nodeName = '#text';
|
|
145
|
+
textNode.value = value;
|
|
146
|
+
textNode.parentNode = this;
|
|
147
|
+
this.childNodes.push(textNode);
|
|
148
|
+
}
|
|
29
149
|
}
|
|
30
150
|
}
|
|
31
151
|
|
|
@@ -34,33 +154,44 @@ class Node extends EventTarget {
|
|
|
34
154
|
class Element extends Node {
|
|
35
155
|
constructor() {
|
|
36
156
|
super();
|
|
37
|
-
this.shadowRoot = null;
|
|
38
|
-
this.innerHTML = '';
|
|
39
|
-
this.attributes = {};
|
|
40
157
|
}
|
|
41
158
|
|
|
42
159
|
attachShadow(options) {
|
|
43
160
|
this.shadowRoot = new ShadowRoot(options);
|
|
44
|
-
|
|
161
|
+
this.shadowRoot.parentNode = this;
|
|
45
162
|
return this.shadowRoot;
|
|
46
163
|
}
|
|
47
164
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
getInnerHTML() {
|
|
51
|
-
return this.shadowRoot ? this.shadowRoot.innerHTML : this.innerHTML;
|
|
165
|
+
getHTML({ serializableShadowRoots = false }) {
|
|
166
|
+
return this.shadowRoot && serializableShadowRoots && this.shadowRoot.serializable ? this.shadowRoot.innerHTML : '';
|
|
52
167
|
}
|
|
53
168
|
|
|
54
|
-
|
|
55
|
-
this.
|
|
169
|
+
get innerHTML() {
|
|
170
|
+
const childNodes = (this.nodeName === 'template' ? this.content : this).childNodes;
|
|
171
|
+
return childNodes ? serialize({ childNodes }) : '';
|
|
56
172
|
}
|
|
57
173
|
|
|
58
|
-
|
|
59
|
-
|
|
174
|
+
set innerHTML(html) {
|
|
175
|
+
(this.nodeName === 'template' ? this.content : this).childNodes = getParse(html)(html).childNodes;
|
|
60
176
|
}
|
|
61
177
|
|
|
62
178
|
hasAttribute(name) {
|
|
63
|
-
return
|
|
179
|
+
return this.attrs.some((attr) => attr.name === name);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
getAttribute(name) {
|
|
183
|
+
const attr = this.attrs.find((attr) => attr.name === name);
|
|
184
|
+
return attr ? attr.value : null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
setAttribute(name, value) {
|
|
188
|
+
const attr = this.attrs?.find((attr) => attr.name === name);
|
|
189
|
+
|
|
190
|
+
if (attr) {
|
|
191
|
+
attr.value = value;
|
|
192
|
+
} else {
|
|
193
|
+
this.attrs?.push({ name, value });
|
|
194
|
+
}
|
|
64
195
|
}
|
|
65
196
|
}
|
|
66
197
|
|
|
@@ -75,7 +206,7 @@ class Document extends Node {
|
|
|
75
206
|
return new HTMLTemplateElement();
|
|
76
207
|
|
|
77
208
|
default:
|
|
78
|
-
return new HTMLElement();
|
|
209
|
+
return new HTMLElement(tagName);
|
|
79
210
|
|
|
80
211
|
}
|
|
81
212
|
}
|
|
@@ -88,6 +219,10 @@ class Document extends Node {
|
|
|
88
219
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
|
|
89
220
|
// EventTarget <- Node <- Element <- HTMLElement
|
|
90
221
|
class HTMLElement extends Element {
|
|
222
|
+
constructor(tagName) {
|
|
223
|
+
super();
|
|
224
|
+
Object.assign(this, getParse5ElementDefaults(this, tagName));
|
|
225
|
+
}
|
|
91
226
|
connectedCallback() { }
|
|
92
227
|
}
|
|
93
228
|
|
|
@@ -100,9 +235,18 @@ class DocumentFragment extends Node { }
|
|
|
100
235
|
class ShadowRoot extends DocumentFragment {
|
|
101
236
|
constructor(options) {
|
|
102
237
|
super();
|
|
103
|
-
this.mode = options.mode
|
|
238
|
+
this.mode = options.mode ?? 'closed';
|
|
239
|
+
this.serializable = options.serializable ?? false;
|
|
104
240
|
this.adoptedStyleSheets = [];
|
|
105
241
|
}
|
|
242
|
+
|
|
243
|
+
get innerHTML() {
|
|
244
|
+
return this.childNodes?.[0]?.content?.childNodes ? serialize({ childNodes: this.childNodes[0].content.childNodes }) : '';
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
set innerHTML(html) {
|
|
248
|
+
this.childNodes = getParse(html)(`<template shadowrootmode="${this.mode}">${html}</template>`).childNodes;
|
|
249
|
+
}
|
|
106
250
|
}
|
|
107
251
|
|
|
108
252
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement
|
|
@@ -110,22 +254,11 @@ class ShadowRoot extends DocumentFragment {
|
|
|
110
254
|
class HTMLTemplateElement extends HTMLElement {
|
|
111
255
|
constructor() {
|
|
112
256
|
super();
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (this.content) {
|
|
119
|
-
this.content.innerHTML = `
|
|
120
|
-
<template shadowrootmode="open">
|
|
121
|
-
${html}
|
|
122
|
-
</template>
|
|
123
|
-
`;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
get innerHTML() {
|
|
128
|
-
return this.content && this.content.innerHTML ? this.content.innerHTML : undefined;
|
|
257
|
+
// Gets element defaults for template element instead of parsing a
|
|
258
|
+
// <template></template> with parse5. Results in better performance
|
|
259
|
+
// when creating templates
|
|
260
|
+
Object.assign(this, getParse5ElementDefaults(this, 'template'));
|
|
261
|
+
this.content.cloneNode = this.cloneNode.bind(this);
|
|
129
262
|
}
|
|
130
263
|
}
|
|
131
264
|
|
|
@@ -156,4 +289,5 @@ globalThis.addEventListener = globalThis.addEventListener ?? noop;
|
|
|
156
289
|
globalThis.document = globalThis.document ?? new Document();
|
|
157
290
|
globalThis.customElements = globalThis.customElements ?? new CustomElementsRegistry();
|
|
158
291
|
globalThis.HTMLElement = globalThis.HTMLElement ?? HTMLElement;
|
|
292
|
+
globalThis.DocumentFragment = globalThis.DocumentFragment ?? DocumentFragment;
|
|
159
293
|
globalThis.CSSStyleSheet = globalThis.CSSStyleSheet ?? CSSStyleSheet;
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type Metadata = {
|
|
2
|
+
[key: string]: {
|
|
3
|
+
instanceName: string;
|
|
4
|
+
moduleURL: URL;
|
|
5
|
+
isEntry: boolean
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type renderToString = (elementURL: URL, wrappingEntryTag?: boolean, props?: any) => Promise<{
|
|
10
|
+
html: string;
|
|
11
|
+
metadata: Metadata
|
|
12
|
+
}>
|
|
13
|
+
|
|
14
|
+
export type renderFromHTML = (html: string, elementURLs: URL[]) => Promise<{
|
|
15
|
+
html: string;
|
|
16
|
+
metadata: Metadata
|
|
17
|
+
}>
|
|
18
|
+
|
|
19
|
+
declare module "wc-compiler" { }
|
package/src/jsx-loader.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable max-depth, complexity */
|
|
2
1
|
// https://nodejs.org/api/esm.html#esm_loaders
|
|
3
2
|
import * as acorn from 'acorn';
|
|
4
3
|
import * as walk from 'acorn-walk';
|
|
@@ -6,6 +5,8 @@ import { generate } from 'astring';
|
|
|
6
5
|
import fs from 'fs';
|
|
7
6
|
// ideally we can eventually adopt an ESM compatible version of this plugin
|
|
8
7
|
// https://github.com/acornjs/acorn-jsx/issues/112
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
// but it does have a default export???
|
|
9
10
|
import jsx from '@projectevergreen/acorn-jsx-esm';
|
|
10
11
|
import { parse, parseFragment, serialize } from 'parse5';
|
|
11
12
|
import { transform } from 'sucrase';
|
|
@@ -138,13 +139,13 @@ function parseJsxElement(element, moduleContents = '') {
|
|
|
138
139
|
const { expression } = value;
|
|
139
140
|
|
|
140
141
|
if (expression.type === 'Identifier') {
|
|
141
|
-
string += ` ${name}
|
|
142
|
+
string += ` ${name}=$\{${expression.name}}`;
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
if (expression.type === 'MemberExpression') {
|
|
145
146
|
if (expression.object.type === 'Identifier') {
|
|
146
147
|
if (expression.property.type === 'Identifier') {
|
|
147
|
-
string += ` ${name}
|
|
148
|
+
string += ` ${name}=$\{${expression.object.name}.${expression.property.name}}`;
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -174,7 +175,7 @@ function parseJsxElement(element, moduleContents = '') {
|
|
|
174
175
|
|
|
175
176
|
if (type === 'Identifier') {
|
|
176
177
|
// You have {count} TODOs left to complete
|
|
177
|
-
string +=
|
|
178
|
+
string += `$\{${element.expression.name}}`;
|
|
178
179
|
} else if (type === 'MemberExpression') {
|
|
179
180
|
const { object } = element.expression.object;
|
|
180
181
|
|
|
@@ -187,7 +188,7 @@ function parseJsxElement(element, moduleContents = '') {
|
|
|
187
188
|
// const { todos } = this;
|
|
188
189
|
// ....
|
|
189
190
|
// You have {todos.length} Todos left to complete
|
|
190
|
-
string +=
|
|
191
|
+
string += `$\{${element.expression.object.name}.${element.expression.property.name}}`;
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
}
|
|
@@ -251,11 +252,13 @@ export function parseJsx(moduleURL) {
|
|
|
251
252
|
|
|
252
253
|
walk.simple(tree, {
|
|
253
254
|
ClassDeclaration(node) {
|
|
255
|
+
// @ts-ignore
|
|
254
256
|
if (node.superClass.name === 'HTMLElement') {
|
|
255
257
|
const hasShadowRoot = moduleContents.slice(node.body.start, node.body.end).indexOf('this.attachShadow(') > 0;
|
|
256
258
|
|
|
257
259
|
for (const n1 of node.body.body) {
|
|
258
260
|
if (n1.type === 'MethodDefinition') {
|
|
261
|
+
// @ts-ignore
|
|
259
262
|
const nodeName = n1.key.name;
|
|
260
263
|
if (nodeName === 'render') {
|
|
261
264
|
for (const n2 in n1.value.body.body) {
|
|
@@ -266,6 +269,7 @@ export function parseJsx(moduleURL) {
|
|
|
266
269
|
...observedAttributes,
|
|
267
270
|
...findThisReferences('render', n)
|
|
268
271
|
];
|
|
272
|
+
// @ts-ignore
|
|
269
273
|
} else if (n.type === 'ReturnStatement' && n.argument.type === 'JSXElement') {
|
|
270
274
|
const html = parseJsxElement(n.argument, moduleContents);
|
|
271
275
|
const elementTree = getParse(html)(html);
|
|
@@ -297,6 +301,7 @@ export function parseJsx(moduleURL) {
|
|
|
297
301
|
sourceType: 'module'
|
|
298
302
|
});
|
|
299
303
|
|
|
304
|
+
// @ts-ignore
|
|
300
305
|
n1.value.body.body[n2] = transformed;
|
|
301
306
|
}
|
|
302
307
|
}
|
|
@@ -309,7 +314,9 @@ export function parseJsx(moduleURL) {
|
|
|
309
314
|
const { declaration } = node;
|
|
310
315
|
|
|
311
316
|
if (declaration && declaration.type === 'VariableDeclaration' && declaration.kind === 'const' && declaration.declarations.length === 1) {
|
|
317
|
+
// @ts-ignore
|
|
312
318
|
if (declaration.declarations[0].id.name === 'inferredObservability') {
|
|
319
|
+
// @ts-ignore
|
|
313
320
|
inferredObservability = Boolean(node.declaration.declarations[0].init.raw);
|
|
314
321
|
}
|
|
315
322
|
}
|
|
@@ -317,6 +324,7 @@ export function parseJsx(moduleURL) {
|
|
|
317
324
|
}, {
|
|
318
325
|
// https://github.com/acornjs/acorn/issues/829#issuecomment-1172586171
|
|
319
326
|
...walk.base,
|
|
327
|
+
// @ts-ignore
|
|
320
328
|
JSXElement: () => {}
|
|
321
329
|
});
|
|
322
330
|
|
|
@@ -325,7 +333,9 @@ export function parseJsx(moduleURL) {
|
|
|
325
333
|
let insertPoint;
|
|
326
334
|
for (const line of tree.body) {
|
|
327
335
|
// test for class MyComponent vs export default class MyComponent
|
|
336
|
+
// @ts-ignore
|
|
328
337
|
if (line.type === 'ClassDeclaration' || (line.declaration && line.declaration.type) === 'ClassDeclaration') {
|
|
338
|
+
// @ts-ignore
|
|
329
339
|
insertPoint = line.declaration.body.start + 1;
|
|
330
340
|
}
|
|
331
341
|
}
|
|
@@ -333,7 +343,6 @@ export function parseJsx(moduleURL) {
|
|
|
333
343
|
let newModuleContents = generate(tree);
|
|
334
344
|
|
|
335
345
|
// TODO better way to determine value type?
|
|
336
|
-
/* eslint-disable indent */
|
|
337
346
|
newModuleContents = `${newModuleContents.slice(0, insertPoint)}
|
|
338
347
|
static get observedAttributes() {
|
|
339
348
|
return [${[...observedAttributes].map(attr => `'${attr}'`).join(',')}]
|
|
@@ -366,7 +375,6 @@ export function parseJsx(moduleURL) {
|
|
|
366
375
|
|
|
367
376
|
${newModuleContents.slice(insertPoint)}
|
|
368
377
|
`;
|
|
369
|
-
/* eslint-enable indent */
|
|
370
378
|
|
|
371
379
|
tree = acorn.Parser.extend(jsx()).parse(newModuleContents, {
|
|
372
380
|
ecmaVersion: 'latest',
|
package/src/register.js
ADDED