Repository: w3c/webidl2.js
Pull request #556 (2021-04-07 11:28:42)

refactor: expose as es module
A maintenance for easier debugging when doing #512.

* This removes 10.x from CI workflow because of no module support, but since this is not dropping the UMD build, it's not a breaking change.
* Refactors `collect()` for module-compatible URL-based approach

Closes #459

saschanaz: I think we can drop `dist/` from git and publish it only to npm, what do you think?

Patch:
diff --git a/.eslintrc.json b/.eslintrc.json
index ae7496c..a9585bd 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -2,8 +2,7 @@
     "env": {
         "browser": true,
         "commonjs": true,
-        "amd": true,
-        "es6": true,
+        "es2020": true,
         "node": true,
         "mocha": true
     },
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index 9338fe6..4d82aae 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -4,12 +4,10 @@ on: [push, pull_request]
 
 jobs:
   build:
-
     runs-on: ubuntu-latest
-
     strategy:
       matrix:
-        node-version: [10.x, 12.x, 14.x]
+        node-version: [12.x, 14.x, 15.x]
 
     steps:
     - uses: actions/checkout@v1
diff --git a/jsconfig.json b/jsconfig.json
index 715f76a..195b3dd 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -1,6 +1,7 @@
 {
   "compilerOptions": {
-    "target": "es2019",
+    "target": "es2020",
+    "module": "es2020",
     "moduleResolution": "node"
   },
   "include": [
diff --git a/lib/validator.js b/lib/validator.js
index d18f265..1353b4f 100644
--- a/lib/validator.js
+++ b/lib/validator.js
@@ -1,5 +1,3 @@
-"use strict";
-
 import { validationError as error } from "./error.js";
 
 function getMixinMap(all, unique) {
diff --git a/lib/webidl2.js b/lib/webidl2.js
index ae0713e..6d0cebe 100644
--- a/lib/webidl2.js
+++ b/lib/webidl2.js
@@ -1,5 +1,3 @@
-"use strict";
-
 import { Tokeniser } from "./tokeniser.js";
 import { Enum } from "./productions/enum.js";
 import { Includes } from "./productions/includes.js";
diff --git a/lib/writer.js b/lib/writer.js
index 88e76ef..6547dd2 100644
--- a/lib/writer.js
+++ b/lib/writer.js
@@ -1,5 +1,3 @@
-"use strict";
-
 function noop(arg) {
   return arg;
 }
diff --git a/package.json b/package.json
index cbe4b42..8e1de2c 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,6 @@
     "Timothy Gu <timothygu99@gmail.com>"
   ],
   "license": "W3C",
-  "dependencies": {},
   "devDependencies": {
     "eslint": "^7.23.0",
     "eslint-plugin-import": "^2.22.1",
@@ -28,11 +27,13 @@
     "test": "npm run lint && webpack && mocha",
     "acquire": "node test/util/acquire.js",
     "build": "npx webpack",
-    "build-debug": "npx webpack --mode none"
+    "build-debug": "npx webpack --mode none",
+    "prepublishOnly": "npm run build"
   },
   "repository": "git://github.com/w3c/webidl2.js",
   "main": "dist/webidl2.js",
-  "module": "index.js",
+  "exports": "./index.js",
+  "type": "module",
   "files": [
     "dist/*",
     "lib/*",


Test patch:
diff --git a/test/autofix.js b/test/autofix.js
index 633ff8e..a4c2eba 100644
--- a/test/autofix.js
+++ b/test/autofix.js
@@ -1,18 +1,16 @@
-"use strict";
-
-const expect = require("expect");
-const webidl2 = require("../dist/webidl2.js");
+import expect from "expect";
+import { parse, validate, write } from "webidl2";
 
 describe("Writer template functions", () => {
   function autofix(idl) {
-    const ast = webidl2.parse(idl, { concrete: true });
-    const validations = webidl2.validate(ast);
+    const ast = parse(idl, { concrete: true });
+    const validations = validate(ast);
     for (const v of validations) {
       if (v.autofix) {
         v.autofix();
       }
     }
-    return webidl2.write(ast);
+    return write(ast);
   }
 
   it("should add `= {}`", () => {
diff --git a/test/invalid.js b/test/invalid.js
index c205d40..1f048dc 100644
--- a/test/invalid.js
+++ b/test/invalid.js
@@ -2,11 +2,9 @@
 //  - the errors actually still need to be reviewed to check that they
 //    are fully correct interpretations of the IDLs
 
-"use strict";
-
-const { collect } = require("./util/collect");
-const { parse, validate, WebIDLParseError } = require("..");
-const expect = require("expect");
+import { collect } from "./util/collect.js";
+import { parse, validate, WebIDLParseError } from "webidl2";
+import expect from "expect";
 
 describe("Parses all of the invalid IDLs to check that they blow up correctly", () => {
   for (const test of collect("invalid", { expectError: true, raw: true })) {
diff --git a/test/parent.js b/test/parent.js
index 331c191..8e7a0b5 100644
--- a/test/parent.js
+++ b/test/parent.js
@@ -1,7 +1,5 @@
-"use strict";
-
-const expect = require("expect");
-const webidl2 = require("../dist/webidl2");
+import expect from "expect";
+import { parse } from "webidl2";
 
 function checkIdlType(idlType) {
   if (idlType.subtype) {
@@ -80,7 +78,7 @@ function checkParent(data) {
  * @param {string} idl
  */
 function parseAndCheck(idl) {
-  const tree = webidl2.parse(idl);
+  const tree = parse(idl);
   for (const item of tree) {
     checkParent(item);
   }
diff --git a/test/syntax.js b/test/syntax.js
index 4ecb386..9eb85a7 100644
--- a/test/syntax.js
+++ b/test/syntax.js
@@ -1,8 +1,6 @@
-"use strict";
-
-const { collect } = require("./util/collect");
-const expect = require("expect");
-const webidl2 = require("../dist/webidl2");
+import { collect } from "./util/collect.js";
+import expect from "expect";
+import { parse } from "webidl2";
 
 describe("Parses all of the IDLs to produce the correct ASTs", () => {
   for (const test of collect("syntax")) {
@@ -14,13 +12,13 @@ describe("Parses all of the IDLs to produce the correct ASTs", () => {
 
 describe("Options", () => {
   it("should emit EOF if concrete", () => {
-    const parsed = webidl2.parse("", { concrete: true });
+    const parsed = parse("", { concrete: true });
     expect(parsed.length).toBe(1);
     expect(parsed[0].type).toBe("eof");
   });
 
   it("should not emit EOF if not concrete", () => {
-    const parsed = webidl2.parse("");
+    const parsed = parse("");
     expect(parsed.length).toBe(0);
   });
 });
diff --git a/test/util/acquire.js b/test/util/acquire.js
index f15e035..780e139 100644
--- a/test/util/acquire.js
+++ b/test/util/acquire.js
@@ -1,10 +1,8 @@
-"use strict";
-
-const { collect } = require("./collect.js");
-const fs = require("fs");
+import { collect } from "./collect.js";
+import { writeFileSync } from "fs";
 
 for (const test of collect("syntax")) {
-  fs.writeFileSync(test.baselinePath, `${JSON.stringify(test.ast, null, 4)}\n`);
+  writeFileSync(test.baselinePath, `${JSON.stringify(test.ast, null, 4)}\n`);
 }
 
 for (const test of collect("invalid", { expectError: true, raw: true })) {
@@ -13,5 +11,5 @@ for (const test of collect("invalid", { expectError: true, raw: true })) {
     test.validation ? test.validation.map(v => `(${v.ruleName}) ${v.message}`).join("\n") :
     "";
 
-  fs.writeFileSync(test.baselinePath, `${content}\n`);
+  writeFileSync(test.baselinePath, `${content}\n`);
 }
diff --git a/test/util/collect.js b/test/util/collect.js
index d99dd71..2ecaf13 100644
--- a/test/util/collect.js
+++ b/test/util/collect.js
@@ -1,26 +1,23 @@
-"use strict";
-
-const wp = require("../../dist/webidl2.js");
-const pth = require("path");
-const fs = require("fs");
-const jdp = require("jsondiffpatch");
+import { parse, validate, WebIDLParseError } from "webidl2";
+import { join, basename } from "path";
+import { readFileSync, readdirSync } from "fs";
+import { diff } from "jsondiffpatch";
 
 /**
  * Collects test items from the specified directory
  * @param {string} base
  */
-function* collect(base, { expectError, raw } = {}) {
-  base = pth.join(__dirname, "..", base);
-  const dir = pth.join(base, "idl");
-  const idls = fs.readdirSync(dir)
-    .filter(it => (/\.webidl$/).test(it))
-    .map(it => pth.join(dir, it));
+export function* collect(base, { expectError, raw } = {}) {
+  const dir = new URL(join("..", base, "idl/"), import.meta.url);
+  const idls = readdirSync(dir)
+    .filter((it) => it.endsWith(".webidl"))
+    .map((it) => new URL(it, dir));
 
   for (const path of idls) {
     try {
-      const text = fs.readFileSync(path, "utf8");
-      const ast = wp.parse(text, { concrete: true, sourceName: pth.basename(path) });
-      const validation = wp.validate(ast);
+      const text = readFileSync(path, "utf8");
+      const ast = parse(text, { concrete: true, sourceName: basename(path.pathname) });
+      const validation = validate(ast);
       if (validation) {
         yield new TestItem({ text, ast, path, validation, raw });
       } else {
@@ -28,7 +25,7 @@ function* collect(base, { expectError, raw } = {}) {
       }
     }
     catch (error) {
-      if (expectError && error instanceof wp.WebIDLParseError) {
+      if (expectError && error instanceof WebIDLParseError) {
         yield new TestItem({ path, error, raw });
       }
       else {
@@ -38,7 +35,6 @@ function* collect(base, { expectError, raw } = {}) {
   }
 }
 
-
 class TestItem {
   constructor({ text, ast, path, error, validation, raw }) {
     this.text = text;
@@ -47,10 +43,12 @@ class TestItem {
     this.error = error;
     this.validation = validation;
     const fileExtension = raw ? ".txt" : ".json";
-    this.baselinePath = pth.join(
-      pth.dirname(path),
-      "../baseline",
-      pth.basename(path).replace(".webidl", fileExtension)
+    this.baselinePath = new URL(
+      join(
+        "../baseline",
+        basename(path.pathname).replace(".webidl", fileExtension)
+      ),
+      path
     );
   }
 
@@ -59,12 +57,10 @@ class TestItem {
   }
 
   readText() {
-    return fs.readFileSync(this.baselinePath, "utf8");
+    return readFileSync(this.baselinePath, "utf8");
   }
 
   diff(target = this.readJSON()) {
-    return jdp.diff(target, this.ast);
+    return diff(target, this.ast);
   }
 }
-
-module.exports.collect = collect;
diff --git a/test/writer.js b/test/writer.js
index c590bb3..999f53c 100644
--- a/test/writer.js
+++ b/test/writer.js
@@ -1,15 +1,13 @@
-"use strict";
-
-const { collect } = require("./util/collect");
-const expect = require("expect");
-const webidl2 = require("../dist/webidl2");
+import { collect } from "./util/collect.js";
+import expect from "expect";
+import { write, parse } from "webidl2";
 
 describe("Rewrite and parses all of the IDLs to produce the same ASTs", () => {
   for (const test of collect("syntax")) {
     it(`should produce the same AST for ${test.path}`, () => {
-      const rewritten = webidl2.write(test.ast);
+      const rewritten = write(test.ast);
       expect(rewritten).toEqual(test.text);
-      const diff = test.diff(webidl2.parse(rewritten, { concrete: true }));
+      const diff = test.diff(parse(rewritten, { concrete: true }));
       expect(diff).toBe(undefined);
     });
   }
@@ -17,8 +15,8 @@ describe("Rewrite and parses all of the IDLs to produce the same ASTs", () => {
 
 describe("Writer template functions", () => {
   function rewrite(text, templates) {
-    const parsed = webidl2.parse(text, { concrete: true });
-    return webidl2.write(parsed, { templates });
+    const parsed = parse(text, { concrete: true });
+    return write(parsed, { templates });
   }
   function bracket(str) {
     return `<${str}>`;