wc-compiler 0.12.1 → 0.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wc-compiler",
3
- "version": "0.12.1",
3
+ "version": "0.14.0",
4
4
  "description": "Experimental native Web Components compiler.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,14 +28,14 @@
28
28
  },
29
29
  "scripts": {
30
30
  "clean": "rimraf ./dist",
31
- "lint": "ls-lint && eslint \"*.*js\" \"./src/**/**/*.js*\" \"./sandbox/**/**/*.js*\" \"./docs/**/*.md\" \"./test/**/**/*.js*\"",
31
+ "lint": "eslint --ignore-pattern \"*.json\" \"*.*js\" \"./src/**/**/*.js*\" \"./sandbox/**/**/*.js*\" \"./docs/**/*.md\" \"./test/**/**/*.js*\"",
32
32
  "docs:dev": "concurrently \"nodemon --watch src --watch docs -e js,md,css,html,jsx ./build.js\" \"http-server ./dist --open\"",
33
33
  "docs:build": "node ./build.js",
34
34
  "docs:serve": "npm run clean && npm run docs:build && http-server ./dist --open",
35
- "sandbox": "npm run clean && concurrently \"nodemon --experimental-loader ./test-exp-loader.js --watch src --watch sandbox -e js,md,css,html,jsx ./sandbox.js\" \"http-server ./dist --open\" \"livereload ./dist\"",
35
+ "sandbox": "npm run clean && concurrently \"nodemon --loader ./test-exp-loader.js --watch src --watch sandbox -e js,md,css,html,jsx,ts ./sandbox.js\" \"http-server ./dist --open\" \"livereload ./dist\"",
36
36
  "start": "npm run docs:serve",
37
- "test": "mocha --exclude \"./test/cases/jsx*/**\" --exclude \"./test/cases/custom-extension/**\" \"./test/**/**/*.spec.js\"",
38
- "test:exp": "c8 node --experimental-loader ./test-exp-loader.js ./node_modules/mocha/bin/mocha \"./test/**/**/*.spec.js\"",
37
+ "test": "mocha --exclude \"./test/cases/jsx*/**\" --exclude \"./test/cases/ts*/**\" --exclude \"./test/cases/custom-extension/**\" \"./test/**/**/*.spec.js\"",
38
+ "test:exp": "c8 node --loader ./test-exp-loader.js ./node_modules/mocha/bin/mocha \"./test/**/**/*.spec.js\"",
39
39
  "test:tdd": "npm run test -- --watch",
40
40
  "test:tdd:exp": "npm run test:exp -- --watch",
41
41
  "dist": "rollup -c rollup.config.js",
@@ -45,10 +45,16 @@
45
45
  "@projectevergreen/acorn-jsx-esm": "~0.1.0",
46
46
  "@projectevergreen/escodegen-esm": "~0.1.0",
47
47
  "acorn": "^8.7.0",
48
+ "acorn-import-attributes": "^1.9.5",
48
49
  "acorn-walk": "^8.2.0",
49
- "parse5": "^6.0.1"
50
+ "parse5": "^6.0.1",
51
+ "sucrase": "^3.35.0"
50
52
  },
51
53
  "devDependencies": {
54
+ "@babel/core": "^7.24.4",
55
+ "@babel/eslint-parser": "^7.24.1",
56
+ "@babel/plugin-syntax-import-assertions": "^7.24.1",
57
+ "@babel/preset-react": "^7.24.1",
52
58
  "@ls-lint/ls-lint": "^1.10.0",
53
59
  "@mapbox/rehype-prism": "^0.8.0",
54
60
  "@rollup/plugin-commonjs": "^25.0.7",
package/src/dom-shim.js CHANGED
@@ -1,5 +1,13 @@
1
1
  function noop() { }
2
2
 
3
+ // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet
4
+ class CSSStyleSheet {
5
+ insertRule() { }
6
+ deleteRule() { }
7
+ replace() { }
8
+ replaceSync() { }
9
+ }
10
+
3
11
  // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
4
12
  class EventTarget {
5
13
  constructor() {
@@ -93,6 +101,7 @@ class ShadowRoot extends DocumentFragment {
93
101
  constructor(options) {
94
102
  super();
95
103
  this.mode = options.mode || 'closed';
104
+ this.adoptedStyleSheets = [];
96
105
  }
97
106
  }
98
107
 
@@ -146,4 +155,5 @@ class CustomElementsRegistry {
146
155
  globalThis.addEventListener = globalThis.addEventListener ?? noop;
147
156
  globalThis.document = globalThis.document ?? new Document();
148
157
  globalThis.customElements = globalThis.customElements ?? new CustomElementsRegistry();
149
- globalThis.HTMLElement = globalThis.HTMLElement ?? HTMLElement;
158
+ globalThis.HTMLElement = globalThis.HTMLElement ?? HTMLElement;
159
+ globalThis.CSSStyleSheet = globalThis.CSSStyleSheet ?? CSSStyleSheet;
package/src/jsx-loader.js CHANGED
@@ -6,6 +6,9 @@ import { generate } from '@projectevergreen/escodegen-esm';
6
6
  import fs from 'fs';
7
7
  import jsx from '@projectevergreen/acorn-jsx-esm';
8
8
  import { parse, parseFragment, serialize } from 'parse5';
9
+ // Need an acorn plugin for now - https://github.com/ProjectEvergreen/greenwood/issues/1218
10
+ import { importAttributes } from 'acorn-import-attributes';
11
+ import { transform } from 'sucrase';
9
12
 
10
13
  const jsxRegex = /\.(jsx)$/;
11
14
 
@@ -29,7 +32,7 @@ export function getParser(moduleURL) {
29
32
  }
30
33
 
31
34
  return {
32
- parser: acorn.Parser.extend(jsx()),
35
+ parser: acorn.Parser.extend(jsx(), importAttributes),
33
36
  config: {
34
37
  // https://github.com/acornjs/acorn/issues/829#issuecomment-1172586171
35
38
  ...walk.base,
@@ -230,13 +233,17 @@ function findThisReferences(context, statement) {
230
233
 
231
234
  export function parseJsx(moduleURL) {
232
235
  const moduleContents = fs.readFileSync(moduleURL, 'utf-8');
236
+ const result = transform(moduleContents, {
237
+ transforms: ['typescript', 'jsx'],
238
+ jsxRuntime: 'preserve'
239
+ });
233
240
  // would be nice if we could do this instead, so we could know ahead of time
234
241
  // const { inferredObservability } = await import(moduleURL);
235
242
  // however, this requires making parseJsx async, but WCC acorn walking is done sync
236
243
  const hasOwnObservedAttributes = undefined;
237
244
  let inferredObservability = false;
238
245
  let observedAttributes = [];
239
- let tree = acorn.Parser.extend(jsx()).parse(moduleContents, {
246
+ let tree = acorn.Parser.extend(jsx(), importAttributes).parse(result.code, {
240
247
  ecmaVersion: 'latest',
241
248
  sourceType: 'module'
242
249
  });
@@ -0,0 +1,32 @@
1
+ import fs from 'fs/promises';
2
+ import { transform } from 'sucrase';
3
+
4
+ const tsRegex = /\.(ts)$/;
5
+
6
+ export function resolve(specifier, context, defaultResolve) {
7
+ const { parentURL } = context;
8
+
9
+ if (tsRegex.test(specifier)) {
10
+ return {
11
+ url: new URL(specifier, parentURL).href,
12
+ shortCircuit: true
13
+ };
14
+ }
15
+
16
+ return defaultResolve(specifier, context, defaultResolve);
17
+ }
18
+
19
+ export async function load(url, context, defaultLoad) {
20
+ if (tsRegex.test(url)) {
21
+ const contents = await fs.readFile(new URL(url), 'utf-8');
22
+ const result = transform(contents, { transforms: ['typescript'] });
23
+
24
+ return {
25
+ format: 'module',
26
+ shortCircuit: true,
27
+ source: result.code
28
+ };
29
+ }
30
+
31
+ return defaultLoad(url, context, defaultLoad);
32
+ }
package/src/wcc.js CHANGED
@@ -7,6 +7,9 @@ import * as walk from 'acorn-walk';
7
7
  import { generate } from '@projectevergreen/escodegen-esm';
8
8
  import { getParser, parseJsx } from './jsx-loader.js';
9
9
  import { parse, parseFragment, serialize } from 'parse5';
10
+ // Need an acorn plugin for now - https://github.com/ProjectEvergreen/greenwood/issues/1218
11
+ import { importAttributes } from 'acorn-import-attributes';
12
+ import { transform } from 'sucrase';
10
13
  import fs from 'fs';
11
14
 
12
15
  function getParse(html) {
@@ -59,14 +62,18 @@ async function renderComponentRoots(tree, definitions) {
59
62
 
60
63
  function registerDependencies(moduleURL, definitions, depth = 0) {
61
64
  const moduleContents = fs.readFileSync(moduleURL, 'utf-8');
65
+ const result = transform(moduleContents, {
66
+ transforms: ['typescript', 'jsx'],
67
+ jsxRuntime: 'preserve'
68
+ });
62
69
  const nextDepth = depth += 1;
63
70
  const customParser = getParser(moduleURL);
64
- const parser = customParser ? customParser.parser : acorn;
71
+ const parser = customParser ? customParser.parser : acorn.Parser;
65
72
  const config = customParser ? customParser.config : {
66
73
  ...walk.base
67
74
  };
68
75
 
69
- walk.simple(parser.parse(moduleContents, {
76
+ walk.simple(parser.extend(importAttributes).parse(result.code, {
70
77
  ecmaVersion: 'latest',
71
78
  sourceType: 'module'
72
79
  }), {
@@ -76,7 +83,8 @@ function registerDependencies(moduleURL, definitions, depth = 0) {
76
83
  const extension = specifier.split('.').pop();
77
84
 
78
85
  // TODO would like to decouple .jsx from the core, ideally
79
- if (!isBareSpecifier && ['js', 'jsx'].includes(extension)) {
86
+ // https://github.com/ProjectEvergreen/wcc/issues/122
87
+ if (!isBareSpecifier && ['js', 'jsx', 'ts'].includes(extension)) {
80
88
  const dependencyModuleURL = new URL(node.source.value, moduleURL);
81
89
 
82
90
  registerDependencies(dependencyModuleURL, definitions, nextDepth);
@@ -105,14 +113,18 @@ function registerDependencies(moduleURL, definitions, depth = 0) {
105
113
 
106
114
  async function getTagName(moduleURL) {
107
115
  const moduleContents = await fs.promises.readFile(moduleURL, 'utf-8');
116
+ const result = transform(moduleContents, {
117
+ transforms: ['typescript', 'jsx'],
118
+ jsxRuntime: 'preserve'
119
+ });
108
120
  const customParser = getParser(moduleURL);
109
- const parser = customParser ? customParser.parser : acorn;
121
+ const parser = customParser ? customParser.parser : acorn.Parser;
110
122
  const config = customParser ? customParser.config : {
111
123
  ...walk.base
112
124
  };
113
125
  let tagName;
114
126
 
115
- walk.simple(parser.parse(moduleContents, {
127
+ walk.simple(parser.extend(importAttributes).parse(result.code, {
116
128
  ecmaVersion: 'latest',
117
129
  sourceType: 'module'
118
130
  }), {
@@ -133,9 +145,10 @@ async function initializeCustomElement(elementURL, tagName, attrs = [], definiti
133
145
  }
134
146
 
135
147
  // https://github.com/ProjectEvergreen/wcc/pull/67/files#r902061804
136
- const { pathname } = elementURL;
137
- const element = customElements.get(tagName) ?? (await import(pathname)).default;
138
- const dataLoader = (await import(pathname)).getData;
148
+ // https://github.com/ProjectEvergreen/wcc/pull/159
149
+ const { href } = elementURL;
150
+ const element = customElements.get(tagName) ?? (await import(href)).default;
151
+ const dataLoader = (await import(href)).getData;
139
152
  const data = props
140
153
  ? props
141
154
  : dataLoader