Repository: karen-irc/option-t
Pull request #1031 (2021-06-06 11:32:32)

Simplify addHistoricalPathToExportsFields() 


Patch:
diff --git a/tools/package_json_rewriter/transformer/add_exports_field/ExportEntry.mjs b/tools/package_json_rewriter/transformer/add_exports_field/ExportEntry.mjs
new file mode 100644
index 00000000..0dd1a019
--- /dev/null
+++ b/tools/package_json_rewriter/transformer/add_exports_field/ExportEntry.mjs
@@ -0,0 +1,102 @@
+import * as assert from 'assert';
+
+import {
+    QuirksLegacyExposedPath
+} from '../../../public_api/mod.mjs';
+
+class AbstractExportEntry {
+    key() {
+        throw new EvalError(`please override on ${this.constructor.name}`);
+    }
+    toJSON() {
+        throw new EvalError(`please override on ${this.constructor.name}`);
+    }
+}
+
+export class ExportEntry extends AbstractExportEntry {
+    constructor(key, path) {
+        super();
+
+        assert.strictEqual(key.startsWith('/'), false, `key (${key}) should not start with /`);
+        assert.strictEqual(key.endsWith('/'), false, `key (${key}) should not end with /`);
+
+        this._key = key;
+        this._path = path;
+    }
+
+    key() {
+        const key = this._key;
+        // For `main` field
+        if (key === '.') {
+            return key;
+        }
+
+        const k = `./${this._key}`;
+        return k;
+    }
+
+    toJSON() {
+        const p = this._path !== null ? this._path : this._key;
+
+        const esm = `./esm/${p}.mjs`;
+        const cjs = `./cjs/${p}.js`;
+
+        // [By the document of Node.js v14.2](https://nodejs.org/api/esm.html#esm_resolution_algorithm),
+        //  * Condition matching is applied in object order from first to last within the "exports" object.
+        //  * `["node", "import"]` is used as _defaultEnv_ for its ES Module resolver.
+        //
+        // see also https://nodejs.org/api/esm.html#esm_conditional_exports
+        return {
+            'import': esm,
+            'require': cjs,
+            // 'default'
+        };
+    }
+}
+
+export class CompatExportEntry extends AbstractExportEntry {
+    constructor(entry) {
+        super();
+        assert.ok(entry instanceof QuirksLegacyExposedPath);
+
+        this._original = entry;
+    }
+
+    key() {
+        const key = this._original.name();
+        const k = `./${key}`;
+        return k;
+    }
+
+    path() {
+        const original = this._original;
+        const hasExtension = original.hasExtension();
+        if (!hasExtension) {
+            return this._pathForNoExtension();
+        }
+
+        const p = this.key();
+        return p;
+    }
+
+    _pathForNoExtension() {
+        const original = this._original;
+        const key = this.key();
+        if (original.isESM()) {
+            const p = `${key}.mjs`;
+            return p;
+        }
+
+        if (original.isCJS()) {
+            const p = `${key}.js`;
+            return p;
+        }
+
+        if (original.isLib()) {
+            const p = `${key}.js`;
+            return p;
+        }
+
+        throw new RangeError('not here');
+    }
+}
diff --git a/tools/package_json_rewriter/transformer/add_exports_field/compatibility.mjs b/tools/package_json_rewriter/transformer/add_exports_field/compatibility.mjs
index 738a6964..d8629834 100644
--- a/tools/package_json_rewriter/transformer/add_exports_field/compatibility.mjs
+++ b/tools/package_json_rewriter/transformer/add_exports_field/compatibility.mjs
@@ -1,34 +1,24 @@
 import * as assert from 'assert';
 
+import { CompatExportEntry } from './ExportEntry.mjs';
+
 const SHOULD_EXPOSE_LIB = true;
 
 export function addHistoricalPathToExportsFields(o, histricalJSPathSeq) {
     // https://nodejs.org/api/esm.html
-    for (const entry of histricalJSPathSeq) {
-        assert.ok(entry.isForCompat());
-        if (entry.isLib()) {
+    for (const original of histricalJSPathSeq) {
+        assert.ok(original.isForCompat());
+        if (original.isLib()) {
             if (!SHOULD_EXPOSE_LIB) {
                 continue;
             }
         }
 
-        if (!entry.hasExtension()) {
-            continue;
-        }
-
-        const file = entry.name();
-        const filepath = `./${file}`;
-        // eslint-disable-next-line no-param-reassign
-        o[filepath] = filepath;
-
-        // Use cjs for lib/
-        if (SHOULD_EXPOSE_LIB && filepath.startsWith('./lib/') && filepath.endsWith('.mjs')) {
-            continue;
-        }
-
-        const filepathWithoutExtension = filepath.replace(/\.(js|mjs|cjs)$/u, '');
+        const entry = new CompatExportEntry(original);
+        const key = entry.key();
+        const filepath = entry.path();
         // eslint-disable-next-line no-param-reassign
-        o[filepathWithoutExtension] = filepath;
+        o[key] = filepath;
     }
 
     const DIR_SUBPATH = [
diff --git a/tools/package_json_rewriter/transformer/add_exports_field/public_api.mjs b/tools/package_json_rewriter/transformer/add_exports_field/public_api.mjs
index d78866cd..0b96e9f1 100644
--- a/tools/package_json_rewriter/transformer/add_exports_field/public_api.mjs
+++ b/tools/package_json_rewriter/transformer/add_exports_field/public_api.mjs
@@ -1,43 +1,6 @@
 import * as assert from 'assert';
 
-class ExportEntity {
-    constructor(key, path) {
-        assert.strictEqual(key.startsWith('/'), false, `key (${key}) should not start with /`);
-        assert.strictEqual(key.endsWith('/'), false, `key (${key}) should not end with /`);
-
-        this._key = key;
-        this._path = path;
-    }
-
-    key() {
-        const key = this._key;
-        // For `main` field
-        if (key === '.') {
-            return key;
-        }
-
-        const k = `./${this._key}`;
-        return k;
-    }
-
-    toJSON() {
-        const p = this._path !== null ? this._path : this._key;
-
-        const esm = `./esm/${p}.mjs`;
-        const cjs = `./cjs/${p}.js`;
-
-        // [By the document of Node.js v14.2](https://nodejs.org/api/esm.html#esm_resolution_algorithm),
-        //  * Condition matching is applied in object order from first to last within the "exports" object.
-        //  * `["node", "import"]` is used as _defaultEnv_ for its ES Module resolver.
-        //
-        // see also https://nodejs.org/api/esm.html#esm_conditional_exports
-        return {
-            'import': esm,
-            'require': cjs,
-            // 'default'
-        };
-    }
-}
+import { ExportEntry } from './ExportEntry.mjs';
 
 export function loadPublicAPIDefinitions(seq) {
     const EXPORT_ENTRIES = [];
@@ -46,7 +9,7 @@ export function loadPublicAPIDefinitions(seq) {
 
         const name = item.name();
         const path = item.path();
-        const entry = new ExportEntity(name, path);
+        const entry = new ExportEntry(name, path);
         EXPORT_ENTRIES.push(entry);
     }
 
diff --git a/tools/public_api/ExposedPath.mjs b/tools/public_api/ExposedPath.mjs
index 4e0b9797..176d7e27 100644
--- a/tools/public_api/ExposedPath.mjs
+++ b/tools/public_api/ExposedPath.mjs
@@ -17,7 +17,7 @@ export class ExposedPath {
         return this._raw.path ?? null;
     }
 
-    getCalcPath() {
+    resolvedName() {
         const raw = this.name();
         if (raw === '.') {
             return PKG_NAME;


Test patch:
diff --git a/tools/test_package_exports.mjs b/tools/test_package_exports.mjs
index d9c3d792..22ff9ec3 100644
--- a/tools/test_package_exports.mjs
+++ b/tools/test_package_exports.mjs
@@ -12,7 +12,7 @@ const require = createRequire(import.meta.url);
 async function tryImportPathAsESM(pathItem) {
     assert.ok(pathItem instanceof ExposedPath);
 
-    const targetPath = pathItem.getCalcPath();
+    const targetPath = pathItem.resolvedName();
     let actualExportedObj;
     await assert.doesNotReject(async () => {
         actualExportedObj = await import(targetPath);
@@ -24,7 +24,7 @@ async function tryImportPathAsESM(pathItem) {
 function tryImportPathAsCJS(pathItem) {
     assert.ok(pathItem instanceof ExposedPath);
 
-    const targetPath = pathItem.getCalcPath();
+    const targetPath = pathItem.resolvedName();
 
     let actualExportedObj;
     assert.doesNotThrow(() => {
@@ -37,7 +37,7 @@ function tryImportPathAsCJS(pathItem) {
 function checkExportedItems(actualExportedObj, pathItem) {
     assert.ok(pathItem instanceof ExposedPath);
 
-    const targetPath = pathItem.getCalcPath();
+    const targetPath = pathItem.resolvedName();
     const rawExpected = pathItem.exports();
     if (!!rawExpected) {
         const expected = rawExpected.sort();
@@ -60,7 +60,7 @@ async function tryImportPathForCompat(pathItem) {
         tryImportPathAsCJS(pathItem);
     }
     else {
-        throw new RangeError(`unreachable, but ${pathItem.getCalcPath()} reach to here`);
+        throw new RangeError(`unreachable, but ${pathItem.resolvedName()} reach to here`);
     }
 }