From a0a401d5052647148388027c72cfc0467376c908 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Mon, 1 Oct 2018 22:12:47 -0700 Subject: [PATCH 1/4] module: support multi-dot file extension ('.coffee.md') in Module.load --- lib/internal/modules/cjs/loader.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 975c688edab3d7..f77ef833684049 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -219,6 +219,22 @@ function tryExtensions(p, exts, isMain) { return false; } +// find the longest (possibly multi-dot) extension registered in +// Module._extensions +function findExtension(filename) { + const name = path.basename(filename); + let currentExtension; + let index; + let startIndex = 0; + while ((index = name.indexOf('.', startIndex)) !== -1) { + startIndex = index + 1; + if (index === 0) continue; // Skip dotfiles like .gitignore + currentExtension = name.slice(index); + if (Module._extensions[currentExtension]) return currentExtension; + } + return '.js'; +} + var warned = false; Module._findPath = function(request, paths, isMain) { if (path.isAbsolute(request)) { @@ -600,8 +616,7 @@ Module.prototype.load = function(filename) { this.filename = filename; this.paths = Module._nodeModulePaths(path.dirname(filename)); - var extension = path.extname(filename) || '.js'; - if (!Module._extensions[extension]) extension = '.js'; + var extension = findExtension(filename); Module._extensions[extension](this, filename); this.loaded = true; From 47ca0eb5ad3d46883ff43d7153c89d91944fe99e Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Tue, 2 Oct 2018 21:54:22 -0700 Subject: [PATCH 2/4] module: tests for multi-dot extensions --- .../test-module-deleted-extensions.js | 18 ----- test/parallel/test-module-multi-extensions.js | 72 +++++++++++++++++++ 2 files changed, 72 insertions(+), 18 deletions(-) delete mode 100644 test/known_issues/test-module-deleted-extensions.js create mode 100644 test/parallel/test-module-multi-extensions.js diff --git a/test/known_issues/test-module-deleted-extensions.js b/test/known_issues/test-module-deleted-extensions.js deleted file mode 100644 index 3a51e8725eec60..00000000000000 --- a/test/known_issues/test-module-deleted-extensions.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; -// Refs: https://github.com/nodejs/node/issues/4778 -const common = require('../common'); -const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); -const tmpdir = require('../common/tmpdir'); -const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); - -tmpdir.refresh(); -fs.writeFileSync(file, '', 'utf8'); -require.extensions['.foo.bar'] = (module, path) => {}; -delete require.extensions['.foo.bar']; -require.extensions['.bar'] = common.mustCall((module, path) => { - assert.strictEqual(module.id, file); - assert.strictEqual(path, file); -}); -require(path.join(tmpdir.path, 'test-extensions')); diff --git a/test/parallel/test-module-multi-extensions.js b/test/parallel/test-module-multi-extensions.js new file mode 100644 index 00000000000000..dc5043a0bb95c5 --- /dev/null +++ b/test/parallel/test-module-multi-extensions.js @@ -0,0 +1,72 @@ +'use strict'; + +// Refs: https://github.com/nodejs/node/issues/4778 + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const Module = require('module'); +const tmpdir = require('../common/tmpdir'); +const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); + +tmpdir.refresh(); +fs.writeFileSync(file, 'console.log(__filename);', 'utf8'); + +{ + require.extensions['.bar'] = common.mustNotCall(); + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions'); + require(modulePath); + require(file); + delete require.cache[file]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions'); + require(modulePath); + assert.throws( + () => require(`${modulePath}.foo`), + new Error(`Cannot find module '${modulePath}.foo'`) + ); + require(`${modulePath}.foo.bar`); + delete require.cache[file]; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + const modulePath = path.join(tmpdir.path, 'test-extensions'); + assert.throws( + () => require(modulePath), + new Error(`Cannot find module '${modulePath}'`) + ); + delete require.cache[file]; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustNotCall(); + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions.foo'); + require(modulePath); + delete require.cache[file]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.foo.bar'] = common.mustNotCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions.foo'); + assert.throws( + () => require(modulePath), + new Error(`Cannot find module '${modulePath}'`) + ); + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} From 06f1afd212d81557427e620cbf70d2de6b34d0f5 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Fri, 12 Oct 2018 17:49:46 -0700 Subject: [PATCH 3/4] module: rename function to be more descriptive --- lib/internal/modules/cjs/loader.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index f77ef833684049..4a5fc596c0511d 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -221,7 +221,7 @@ function tryExtensions(p, exts, isMain) { // find the longest (possibly multi-dot) extension registered in // Module._extensions -function findExtension(filename) { +function findLongestRegisteredExtension(filename) { const name = path.basename(filename); let currentExtension; let index; @@ -616,7 +616,7 @@ Module.prototype.load = function(filename) { this.filename = filename; this.paths = Module._nodeModulePaths(path.dirname(filename)); - var extension = findExtension(filename); + var extension = findLongestRegisteredExtension(filename); Module._extensions[extension](this, filename); this.loaded = true; From 64aab099766944c370c3038fa590f3f5da006ee1 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Tue, 23 Oct 2018 16:21:26 -0700 Subject: [PATCH 4/4] module: dotfile tests --- test/parallel/test-module-multi-extensions.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/parallel/test-module-multi-extensions.js b/test/parallel/test-module-multi-extensions.js index dc5043a0bb95c5..be17bc5d025508 100644 --- a/test/parallel/test-module-multi-extensions.js +++ b/test/parallel/test-module-multi-extensions.js @@ -9,9 +9,13 @@ const path = require('path'); const Module = require('module'); const tmpdir = require('../common/tmpdir'); const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); +const dotfile = path.join(tmpdir.path, '.bar'); +const dotfileWithExtension = path.join(tmpdir.path, '.foo.bar'); tmpdir.refresh(); fs.writeFileSync(file, 'console.log(__filename);', 'utf8'); +fs.writeFileSync(dotfile, 'console.log(__filename);', 'utf8'); +fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); { require.extensions['.bar'] = common.mustNotCall(); @@ -70,3 +74,21 @@ fs.writeFileSync(file, 'console.log(__filename);', 'utf8'); delete require.extensions['.foo.bar']; Module._pathCache = Object.create(null); } + +{ + require.extensions['.bar'] = common.mustNotCall(); + require(dotfile); + delete require.cache[dotfile]; + delete require.extensions['.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustCall(); + require.extensions['.foo.bar'] = common.mustNotCall(); + require(dotfileWithExtension); + delete require.cache[dotfileWithExtension]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +}