129 lines
2.7 KiB
JavaScript
129 lines
2.7 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const Walker = require('node-source-walk');
|
||
|
const types = require('ast-module-types');
|
||
|
const fs = require('fs');
|
||
|
|
||
|
/**
|
||
|
* Determines the type of the module from the supplied source code or AST
|
||
|
*
|
||
|
* @param {String|Object} source - The string content or AST of a file
|
||
|
* @return {String}
|
||
|
*/
|
||
|
function fromSource(source) {
|
||
|
if (typeof source === 'undefined') {
|
||
|
throw new Error('source not supplied');
|
||
|
}
|
||
|
|
||
|
const walker = new Walker();
|
||
|
let type = 'none';
|
||
|
let hasDefine = false;
|
||
|
let hasAMDTopLevelRequire = false;
|
||
|
let hasRequire = false;
|
||
|
let hasExports = false;
|
||
|
let hasES6Import = false;
|
||
|
let hasES6Export = false;
|
||
|
let hasDynamicImport = false;
|
||
|
|
||
|
// Walker accepts as AST to avoid reparsing
|
||
|
walker.walk(source, function(node) {
|
||
|
if (types.isDefine(node)) {
|
||
|
hasDefine = true;
|
||
|
}
|
||
|
|
||
|
if (types.isRequire(node)) {
|
||
|
hasRequire = true;
|
||
|
}
|
||
|
|
||
|
if (types.isExports(node)) {
|
||
|
hasExports = true;
|
||
|
}
|
||
|
|
||
|
if (types.isAMDDriverScriptRequire(node)) {
|
||
|
hasAMDTopLevelRequire = true;
|
||
|
}
|
||
|
|
||
|
if (types.isES6Import(node)) {
|
||
|
hasES6Import = true;
|
||
|
}
|
||
|
|
||
|
if (types.isES6Export(node)) {
|
||
|
hasES6Export = true;
|
||
|
}
|
||
|
|
||
|
if (hasES6Import || hasES6Export || hasDynamicImport) {
|
||
|
type = 'es6';
|
||
|
walker.stopWalking();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (hasDefine || hasAMDTopLevelRequire) {
|
||
|
type = 'amd';
|
||
|
walker.stopWalking();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (hasExports || (hasRequire && !hasDefine)) {
|
||
|
type = 'commonjs';
|
||
|
walker.stopWalking();
|
||
|
return;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return type;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Synchronously determine the module type for the contents of the passed filepath
|
||
|
*
|
||
|
* @param {String} file
|
||
|
* @param {Object} options
|
||
|
* @return {String}
|
||
|
*/
|
||
|
function sync(file, options) {
|
||
|
if (!file) {
|
||
|
throw new Error('filename missing');
|
||
|
}
|
||
|
var fileSystem = options ? (options.fileSystem || fs) : fs;
|
||
|
const data = fileSystem.readFileSync(file, 'utf8');
|
||
|
return fromSource(data.toString());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Asynchronously determines the module type for the contents of the given filepath
|
||
|
*
|
||
|
* @param {String} filepath
|
||
|
* @param {Function} cb - Executed with (err, type)
|
||
|
*/
|
||
|
module.exports = function(filepath, cb, options) {
|
||
|
if (!filepath) {
|
||
|
throw new Error('filename missing');
|
||
|
}
|
||
|
|
||
|
if (!cb) {
|
||
|
throw new Error('callback missing');
|
||
|
}
|
||
|
|
||
|
const opts = {encoding: 'utf8'};
|
||
|
var fileSystem = options ? (options.fileSystem || fs) : fs;
|
||
|
|
||
|
fileSystem.readFile(filepath, opts, function(err, data) {
|
||
|
if (err) {
|
||
|
return cb(err);
|
||
|
}
|
||
|
|
||
|
let type;
|
||
|
|
||
|
try {
|
||
|
type = fromSource(data);
|
||
|
} catch (error) {
|
||
|
return cb(error);
|
||
|
}
|
||
|
|
||
|
cb(null, type);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
module.exports.sync = sync;
|
||
|
module.exports.fromSource = fromSource;
|