Skip to content

Commit

Permalink
module: support multi-dot file extension
Browse files Browse the repository at this point in the history
Support multi-dot file extensions like '.coffee.md' in Module.load.

PR-URL: #23416
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
  • Loading branch information
GeoffreyBooth authored and targos committed Nov 2, 2018
1 parent 8bffd90 commit 1dd8191
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 20 deletions.
19 changes: 17 additions & 2 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,22 @@ function tryExtensions(p, exts, isMain) {
return false;
}

// find the longest (possibly multi-dot) extension registered in
// Module._extensions
function findLongestRegisteredExtension(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)) {
Expand Down Expand Up @@ -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 = findLongestRegisteredExtension(filename);
Module._extensions[extension](this, filename);
this.loaded = true;

Expand Down
18 changes: 0 additions & 18 deletions test/known_issues/test-module-deleted-extensions.js

This file was deleted.

94 changes: 94 additions & 0 deletions test/parallel/test-module-multi-extensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'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');
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();
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);
}

{
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);
}

0 comments on commit 1dd8191

Please sign in to comment.