wc-compiler 0.4.0 → 0.6.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/src/wcc.js CHANGED
@@ -1,12 +1,13 @@
1
+ /* eslint-disable max-depth */
1
2
  // this must come first
2
3
  import './dom-shim.js';
3
4
 
4
5
  import * as acorn from 'acorn';
5
6
  import * as walk from 'acorn-walk';
7
+ import escodegen from 'escodegen';
8
+ import { getParser, parseJsx } from './jsx-loader.js';
6
9
  import { parse, parseFragment, serialize } from 'parse5';
7
- import fs from 'fs/promises';
8
-
9
- let definitions;
10
+ import fs from 'fs';
10
11
 
11
12
  function getParse(html) {
12
13
  return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
@@ -22,87 +23,110 @@ function isCustomElementDefinitionNode(node) {
22
23
  && expression.callee.property.name === 'define';
23
24
  }
24
25
 
25
- async function renderComponentRoots(tree) {
26
+ async function renderComponentRoots(tree, definitions) {
26
27
  for (const node of tree.childNodes) {
27
28
  if (node.tagName && node.tagName.indexOf('-') > 0) {
28
29
  const { tagName } = node;
29
- const { moduleURL } = definitions[tagName];
30
- const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs);
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];
30
+
31
+ if (definitions[tagName]) {
32
+ const { moduleURL } = definitions[tagName];
33
+ const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
34
+ const elementHtml = elementInstance.shadowRoot
35
+ ? elementInstance.getInnerHTML({ includeShadowRoots: true })
36
+ : elementInstance.innerHTML;
37
+ const elementTree = parseFragment(elementHtml);
38
+
39
+ node.childNodes = node.childNodes.length === 0
40
+ ? elementTree.childNodes
41
+ : [...elementTree.childNodes, ...node.childNodes];
42
+ } else {
43
+ console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
44
+ }
39
45
  }
40
46
 
41
47
  if (node.childNodes && node.childNodes.length > 0) {
42
- await renderComponentRoots(node);
48
+ await renderComponentRoots(node, definitions);
43
49
  }
44
50
 
45
51
  // does this only apply to `<template>` tags?
46
52
  if (node.content && node.content.childNodes && node.content.childNodes.length > 0) {
47
- await renderComponentRoots(node.content);
53
+ await renderComponentRoots(node.content, definitions);
48
54
  }
49
55
  }
50
56
 
51
57
  return tree;
52
58
  }
53
59
 
54
- async function registerDependencies(moduleURL) {
55
- const moduleContents = await fs.readFile(moduleURL, 'utf-8');
60
+ function registerDependencies(moduleURL, definitions, depth = 0) {
61
+ const moduleContents = fs.readFileSync(moduleURL, 'utf-8');
62
+ const nextDepth = depth += 1;
63
+ const customParser = getParser(moduleURL);
64
+ const parser = customParser ? customParser.parser : acorn;
65
+ const config = customParser ? customParser.config : {
66
+ ...walk.base
67
+ };
56
68
 
57
- walk.simple(acorn.parse(moduleContents, {
69
+ walk.simple(parser.parse(moduleContents, {
58
70
  ecmaVersion: 'latest',
59
71
  sourceType: 'module'
60
72
  }), {
61
- async ImportDeclaration(node) {
73
+ ImportDeclaration(node) {
62
74
  const specifier = node.source.value;
63
75
  const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
64
76
 
65
77
  if (!isBareSpecifier) {
66
78
  const dependencyModuleURL = new URL(node.source.value, moduleURL);
67
79
 
68
- await registerDependencies(dependencyModuleURL);
80
+ registerDependencies(dependencyModuleURL, definitions, nextDepth);
69
81
  }
70
82
  },
71
- async ExpressionStatement(node) {
83
+ ExpressionStatement(node) {
72
84
  if (isCustomElementDefinitionNode(node)) {
73
85
  const { arguments: args } = node.expression;
74
86
  const tagName = args[0].value;
87
+ const tree = parseJsx(moduleURL);
88
+ const isEntry = nextDepth - 1 === 1;
75
89
 
76
90
  definitions[tagName] = {
77
91
  instanceName: args[1].name,
78
- moduleURL
92
+ moduleURL,
93
+ source: escodegen.generate(tree),
94
+ url: moduleURL,
95
+ isEntry
79
96
  };
80
97
  }
81
98
  }
82
- });
99
+ }, config);
83
100
  }
84
101
 
85
102
  async function getTagName(moduleURL) {
86
- const moduleContents = await fs.readFile(moduleURL, 'utf-8');
103
+ const moduleContents = await fs.promises.readFile(moduleURL, 'utf-8');
104
+ const customParser = getParser(moduleURL);
105
+ const parser = customParser ? customParser.parser : acorn;
106
+ const config = customParser ? customParser.config : {
107
+ ...walk.base
108
+ };
87
109
  let tagName;
88
110
 
89
- walk.simple(acorn.parse(moduleContents, {
111
+ walk.simple(parser.parse(moduleContents, {
90
112
  ecmaVersion: 'latest',
91
113
  sourceType: 'module'
92
114
  }), {
93
- async ExpressionStatement(node) {
115
+ ExpressionStatement(node) {
94
116
  if (isCustomElementDefinitionNode(node)) {
95
-
96
117
  tagName = node.expression.arguments[0].value;
97
118
  }
98
119
  }
99
- });
120
+ }, config);
100
121
 
101
122
  return tagName;
102
123
  }
103
124
 
104
- async function initializeCustomElement(elementURL, tagName, attrs = []) {
105
- await registerDependencies(elementURL);
125
+ async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = [], isEntry) {
126
+ if (!tagName) {
127
+ const depth = isEntry ? 1 : 0;
128
+ registerDependencies(elementURL, definitions, depth);
129
+ }
106
130
 
107
131
  // https://github.com/ProjectEvergreen/wcc/pull/67/files#r902061804
108
132
  const { pathname } = elementURL;
@@ -127,16 +151,16 @@ async function initializeCustomElement(elementURL, tagName, attrs = []) {
127
151
  }
128
152
 
129
153
  async function renderToString(elementURL) {
130
- definitions = [];
131
-
154
+ const definitions = [];
132
155
  const elementTagName = await getTagName(elementURL);
133
- const elementInstance = await initializeCustomElement(elementURL);
156
+ const isEntry = !!elementTagName;
157
+ const elementInstance = await initializeCustomElement(elementURL, undefined, undefined, definitions, isEntry);
134
158
 
135
159
  const elementHtml = elementInstance.shadowRoot
136
160
  ? elementInstance.getInnerHTML({ includeShadowRoots: true })
137
161
  : elementInstance.innerHTML;
138
162
  const elementTree = getParse(elementHtml)(elementHtml);
139
- const finalTree = await renderComponentRoots(elementTree);
163
+ const finalTree = await renderComponentRoots(elementTree, definitions);
140
164
  const html = elementTagName ? `
141
165
  <${elementTagName}>
142
166
  ${serialize(finalTree)}
@@ -151,14 +175,14 @@ async function renderToString(elementURL) {
151
175
  }
152
176
 
153
177
  async function renderFromHTML(html, elements = []) {
154
- definitions = [];
178
+ const definitions = [];
155
179
 
156
180
  for (const url of elements) {
157
- await initializeCustomElement(url);
181
+ await initializeCustomElement(url, undefined, undefined, definitions, true);
158
182
  }
159
183
 
160
184
  const elementTree = getParse(html)(html);
161
- const finalTree = await renderComponentRoots(elementTree);
185
+ const finalTree = await renderComponentRoots(elementTree, definitions);
162
186
 
163
187
  return {
164
188
  html: serialize(finalTree),