Skip to content

Commit

Permalink
feat: support es modules without .mjs extension
Browse files Browse the repository at this point in the history
  • Loading branch information
snyamathi committed Nov 6, 2021
1 parent 476214a commit b22d6d8
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 68 deletions.
61 changes: 6 additions & 55 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,8 @@ var libfs = require('fs'),
libcache = require('./cache'),
deepFreeze = require('deep-freeze'),
promisify = require('util').promisify,
mjs = require('./mjs'),

MESSAGES = {
'unknown bundle': 'Unknown bundle "%s"',
'unknown config': 'Unknown config "%s" in bundle "%s"',
'unknown cache data': 'Unknown cache data with config "%s" in bundle "%s"',
'missing dimensions': 'Failed to find a dimensions.json file',
'parse error': 'Failed to parse "%s"\n%s',
'missing time': 'No time dimension, %s, in context, %s, during time aware mode'
},
loadModule = require('./mod'),
MESSAGES = require('./messages'),
DEFAULT_CACHE_OPTIONS = {
max: 250
};
Expand All @@ -35,37 +27,6 @@ function clone(o) {
return JSON.parse(JSON.stringify(o));
}

/**
* Require the export of a CJS module or default export of a transpiled ESModule
* @param {String} id module name or path
* @returns {*} exported module content
*/
function interopRequireDefault(id) {
var obj = require(id);
if (obj.__esModule) {
return obj.default;
}
return obj;
}

/**
* Import an untranspiled ES Module
* @param {String} id module name or path
* @param {Function} [callback] Called once the config has been added to the helper.
* @param {Error|null} callback.err If an error occurred, then this parameter will
* contain the error. If the operation succeeded, then `err` will be null.
* @param {Object} callback.contents The contents of the config file, as a
* JavaScript object.
*/
function importMjs(id, callback) {
mjs(id, function (err, obj) {
if (err) {
return callback(new Error(util.format(MESSAGES['parse error'], id, err.message)));
}
callback(null, obj.default);
});
}

function mix(target, source, overwrite) {
var prop;
for (prop in source) {
Expand Down Expand Up @@ -644,16 +605,8 @@ Config.prototype = {
return callback(err, contents);
});
});
} else if (ext === '.mjs') {
return importMjs(path, callback);
} else {
try {
contents = interopRequireDefault(path);
} catch (e) {
return callback(new Error(util.format(MESSAGES['parse error'], path, e.message)));
}

return callback(null, contents);
} else {
return loadModule(path, callback);
}
},

Expand All @@ -669,10 +622,8 @@ Config.prototype = {
contents = JSON.parse(contents);
} else if ('.json5' === ext) {
contents = libjson5.parse(contents);
} else if ('.mjs' === ext) {
return importMjs(path, callback);
} else if ('.js' === ext) {
contents = interopRequireDefault(path);
} else if ('.mjs' === ext || '.js' === ext) {
return loadModule(path, callback);
} else {
contents = libyaml.parse(contents);
}
Expand Down
8 changes: 8 additions & 0 deletions lib/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
'unknown bundle': 'Unknown bundle "%s"',
'unknown config': 'Unknown config "%s" in bundle "%s"',
'unknown cache data': 'Unknown cache data with config "%s" in bundle "%s"',
'missing dimensions': 'Failed to find a dimensions.json file',
'parse error': 'Failed to parse "%s"\n%s',
'missing time': 'No time dimension, %s, in context, %s, during time aware mode'
};
3 changes: 0 additions & 3 deletions lib/mjs/legacy.js

This file was deleted.

7 changes: 0 additions & 7 deletions lib/mjs/modern.js

This file was deleted.

File renamed without changes.
19 changes: 19 additions & 0 deletions lib/mod/legacy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
var utils = require('./utils');

/**
* Import a CommonJS config
* @param {String} id module name or path
* @param {Function} [callback] Called once the config has been added to the helper.
* @param {Error|null} callback.err If an error occurred, then this parameter will
* contain the error. If the operation succeeded, then `err` will be null.
* @param {Object} callback.contents The contents of the config file, as a
* JavaScript object.
*/
module.exports = function(id, callback) {
try {
var mod = utils.interopDefault(require(id));
callback(null, mod);
} catch (e) {
callback(new utils.ParseError(e, id));
}
}
19 changes: 19 additions & 0 deletions lib/mod/modern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { interopDefault, ParseError } = require('./utils');

/**
* Import an ESModule config.
* @param {String} id module name or path
* @param {Function} [callback] Called once the config has been added to the helper.
* @param {Error|null} callback.err If an error occurred, then this parameter will
* contain the error. If the operation succeeded, then `err` will be null.
* @param {Object} callback.contents The contents of the config file, as a
* JavaScript object.
*/
module.exports = async (id, callback) => {
try {
const mod = interopDefault(await import(id));
callback(null, mod.default);
} catch (e) {
callback(new ParseError(e, id));
}
}
23 changes: 23 additions & 0 deletions lib/mod/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var MESSAGES = require('../messages');
var util = require('util');

/**
* Return the export of a CJS module or default export of a transpiled ESModule
* See https://babeljs.io/docs/en/babel-plugin-transform-modules-commonjs
* @param {Object} mod module
* @returns {*} exported module content
*/
module.exports.interopDefault = function interopDefault(mod) {
if (mod && mod.__esModule) {
return mod.default;
}
return mod;
}

module.exports.ParseError = (function () {
function ParseError(e, id) {
this.message = util.format(MESSAGES['parse error'], id, e.message)
}
ParseError.prototype = new Error;
return ParseError;
})();
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ycb-config",
"version": "2.2.0",
"version": "2.3.0",
"description": "Configuration manager for Yahoo configuration bundles",
"author": "Drew Folta <folta@yahoo-inc.com>",
"contributors": [],
Expand Down
4 changes: 2 additions & 2 deletions tests/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ describe('config', function () {
next(err);
}
} else {
expect(err).to.be.an('error');
expect(err.message).to.include('Node >= 12 is required to import .mjs file');
expect(err).to.be.an.instanceof(Error);
expect(err.message).to.include('Unexpected token export');
next();
}
});
Expand Down

0 comments on commit b22d6d8

Please sign in to comment.