From f074612b744fecfd1f79fd05d7f10fe9a1487e5a Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sun, 22 Apr 2018 18:56:42 -0500 Subject: esm: provide named exports for builtin libs Provide named exports for all builtin libraries so that the libraries may be imported in a nicer way for esm users. The default export is left as the entire namespace (module.exports) and wrapped in a proxy such that APMs and other behavior are still left intact. PR-URL: https://github.com/nodejs/node/pull/20403 Reviewed-By: Bradley Farias Reviewed-By: Guy Bedford Reviewed-By: Jan Krems --- test/es-module/test-esm-dynamic-import.js | 1 + test/es-module/test-esm-live-binding.mjs | 143 ++++++++++++++++++++++++++++++ test/es-module/test-esm-namespace.mjs | 10 ++- 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 test/es-module/test-esm-live-binding.mjs (limited to 'test/es-module') diff --git a/test/es-module/test-esm-dynamic-import.js b/test/es-module/test-esm-dynamic-import.js index c6daa95f9a..9175717288 100644 --- a/test/es-module/test-esm-dynamic-import.js +++ b/test/es-module/test-esm-dynamic-import.js @@ -52,6 +52,7 @@ function expectFsNamespace(result) { Promise.resolve(result) .then(common.mustCall(ns => { assert.strictEqual(typeof ns.default.writeFile, 'function'); + assert.strictEqual(typeof ns.writeFile, 'function'); })); } diff --git a/test/es-module/test-esm-live-binding.mjs b/test/es-module/test-esm-live-binding.mjs new file mode 100644 index 0000000000..d151e004df --- /dev/null +++ b/test/es-module/test-esm-live-binding.mjs @@ -0,0 +1,143 @@ +// Flags: --experimental-modules + +import '../common'; +import assert from 'assert'; + +import fs, { readFile, readFileSync } from 'fs'; +import events, { defaultMaxListeners } from 'events'; +import util from 'util'; + +const readFileDescriptor = Reflect.getOwnPropertyDescriptor(fs, 'readFile'); +const readFileSyncDescriptor = + Reflect.getOwnPropertyDescriptor(fs, 'readFileSync'); + +const s = Symbol(); +const fn = () => s; + +Reflect.deleteProperty(fs, 'readFile'); + +assert.deepStrictEqual([fs.readFile, readFile], [undefined, undefined]); + +fs.readFile = fn; + +assert.deepStrictEqual([fs.readFile(), readFile()], [s, s]); + +Reflect.defineProperty(fs, 'readFile', { + value: fn, + configurable: true, + writable: true, +}); + +assert.deepStrictEqual([fs.readFile(), readFile()], [s, s]); + +Reflect.deleteProperty(fs, 'readFile'); + +assert.deepStrictEqual([fs.readFile, readFile], [undefined, undefined]); + +let count = 0; + +Reflect.defineProperty(fs, 'readFile', { + get() { return count; }, + configurable: true, +}); + +count++; + +assert.deepStrictEqual([readFile, fs.readFile, readFile], [0, 1, 1]); + +let otherValue; + +Reflect.defineProperty(fs, 'readFile', { // eslint-disable-line accessor-pairs + set(value) { + Reflect.deleteProperty(fs, 'readFile'); + otherValue = value; + }, + configurable: true, +}); + +Reflect.defineProperty(fs, 'readFileSync', { + get() { + return otherValue; + }, + configurable: true, +}); + +fs.readFile = 2; + +assert.deepStrictEqual([readFile, readFileSync], [undefined, 2]); + +Reflect.defineProperty(fs, 'readFile', readFileDescriptor); +Reflect.defineProperty(fs, 'readFileSync', readFileSyncDescriptor); + +const originDefaultMaxListeners = events.defaultMaxListeners; +const utilProto = util.__proto__; // eslint-disable-line no-proto + +count = 0; + +Reflect.defineProperty(Function.prototype, 'defaultMaxListeners', { + configurable: true, + enumerable: true, + get: function() { return ++count; }, + set: function(v) { + Reflect.defineProperty(this, 'defaultMaxListeners', { + configurable: true, + enumerable: true, + writable: true, + value: v, + }); + }, +}); + +assert.strictEqual(defaultMaxListeners, originDefaultMaxListeners); +assert.strictEqual(events.defaultMaxListeners, originDefaultMaxListeners); + +assert.strictEqual(++events.defaultMaxListeners, + originDefaultMaxListeners + 1); + +assert.strictEqual(defaultMaxListeners, originDefaultMaxListeners + 1); +assert.strictEqual(Function.prototype.defaultMaxListeners, 1); + +Function.prototype.defaultMaxListeners = 'foo'; + +assert.strictEqual(Function.prototype.defaultMaxListeners, 'foo'); +assert.strictEqual(events.defaultMaxListeners, originDefaultMaxListeners + 1); +assert.strictEqual(defaultMaxListeners, originDefaultMaxListeners + 1); + +count = 0; + +const p = { + get foo() { return ++count; }, + set foo(v) { + Reflect.defineProperty(this, 'foo', { + configurable: true, + enumerable: true, + writable: true, + value: v, + }); + }, +}; + +util.__proto__ = p; // eslint-disable-line no-proto + +assert.strictEqual(util.foo, 1); + +util.foo = 'bar'; + +assert.strictEqual(count, 1); +assert.strictEqual(util.foo, 'bar'); +assert.strictEqual(p.foo, 2); + +p.foo = 'foo'; + +assert.strictEqual(p.foo, 'foo'); + +events.defaultMaxListeners = originDefaultMaxListeners; +util.__proto__ = utilProto; // eslint-disable-line no-proto + +Reflect.deleteProperty(util, 'foo'); +Reflect.deleteProperty(Function.prototype, 'defaultMaxListeners'); + +assert.throws( + () => Object.defineProperty(events, 'defaultMaxListeners', { value: 3 }), + /TypeError: Cannot redefine/ +); diff --git a/test/es-module/test-esm-namespace.mjs b/test/es-module/test-esm-namespace.mjs index 04845e2b3e..dcd159f6c8 100644 --- a/test/es-module/test-esm-namespace.mjs +++ b/test/es-module/test-esm-namespace.mjs @@ -2,5 +2,13 @@ import '../common'; import * as fs from 'fs'; import assert from 'assert'; +import Module from 'module'; -assert.deepStrictEqual(Object.keys(fs), ['default']); +const keys = Object.entries( + Object.getOwnPropertyDescriptors(new Module().require('fs'))) + .filter(([name, d]) => d.enumerable) + .map(([name]) => name) + .concat('default') + .sort(); + +assert.deepStrictEqual(Object.keys(fs).sort(), keys); -- cgit v1.2.3