Provide options.scriptExtensions
This commit is contained in:
parent
cda21ea481
commit
95e5201255
102
lib/compiler.js
102
lib/compiler.js
|
@ -17,6 +17,13 @@ var g = require('strong-globalize')();
|
||||||
|
|
||||||
var FILE_EXTENSION_JSON = '.json';
|
var FILE_EXTENSION_JSON = '.json';
|
||||||
|
|
||||||
|
function arrayToObject(array) {
|
||||||
|
return array.reduce(function(obj, val) {
|
||||||
|
obj[val] = val;
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gather all bootstrap-related configuration data and compile it into
|
* Gather all bootstrap-related configuration data and compile it into
|
||||||
* a single object containing instruction for `boot.execute`.
|
* a single object containing instruction for `boot.execute`.
|
||||||
|
@ -36,8 +43,14 @@ module.exports = function compile(options) {
|
||||||
options = { appRootDir: options };
|
options = { appRootDir: options };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For setting properties without modifying the original object
|
||||||
|
options = Object.create(options);
|
||||||
|
|
||||||
var appRootDir = options.appRootDir = options.appRootDir || process.cwd();
|
var appRootDir = options.appRootDir = options.appRootDir || process.cwd();
|
||||||
var env = options.env || process.env.NODE_ENV || 'development';
|
var env = options.env || process.env.NODE_ENV || 'development';
|
||||||
|
var scriptExtensions = options.scriptExtensions ?
|
||||||
|
arrayToObject(options.scriptExtensions) :
|
||||||
|
require.extensions;
|
||||||
|
|
||||||
var appConfigRootDir = options.appConfigRootDir || appRootDir;
|
var appConfigRootDir = options.appConfigRootDir || appRootDir;
|
||||||
var appConfig = options.config ||
|
var appConfig = options.config ||
|
||||||
|
@ -76,9 +89,9 @@ module.exports = function compile(options) {
|
||||||
resolveRelativePaths(bootScripts, appRootDir);
|
resolveRelativePaths(bootScripts, appRootDir);
|
||||||
|
|
||||||
bootDirs.forEach(function(dir) {
|
bootDirs.forEach(function(dir) {
|
||||||
bootScripts = bootScripts.concat(findScripts(dir));
|
bootScripts = bootScripts.concat(findScripts(dir, scriptExtensions));
|
||||||
var envdir = dir + '/' + env;
|
var envdir = dir + '/' + env;
|
||||||
bootScripts = bootScripts.concat(findScripts(envdir));
|
bootScripts = bootScripts.concat(findScripts(envdir, scriptExtensions));
|
||||||
});
|
});
|
||||||
|
|
||||||
// de-dedup boot scripts -ERS
|
// de-dedup boot scripts -ERS
|
||||||
|
@ -90,12 +103,12 @@ module.exports = function compile(options) {
|
||||||
|
|
||||||
var modelSources = options.modelSources || modelsMeta.sources || ['./models'];
|
var modelSources = options.modelSources || modelsMeta.sources || ['./models'];
|
||||||
var modelInstructions = buildAllModelInstructions(
|
var modelInstructions = buildAllModelInstructions(
|
||||||
modelsRootDir, modelsConfig, modelSources, options.modelDefinitions);
|
modelsRootDir, modelsConfig, modelSources, options.modelDefinitions,
|
||||||
|
scriptExtensions);
|
||||||
|
|
||||||
var mixinDirs = options.mixinDirs || [];
|
|
||||||
var mixinSources = options.mixinSources || modelsMeta.mixins || ['./mixins'];
|
var mixinSources = options.mixinSources || modelsMeta.mixins || ['./mixins'];
|
||||||
var mixinInstructions = buildAllMixinInstructions(
|
var mixinInstructions = buildAllMixinInstructions(
|
||||||
appRootDir, mixinDirs, mixinSources, options, modelInstructions);
|
appRootDir, options, mixinSources, scriptExtensions, modelInstructions);
|
||||||
|
|
||||||
// When executor passes the instruction to loopback methods,
|
// When executor passes the instruction to loopback methods,
|
||||||
// loopback modifies the data. Since we are loading the data using `require`,
|
// loopback modifies the data. Since we are loading the data using `require`,
|
||||||
|
@ -151,11 +164,11 @@ function assertIsValidModelConfig(config) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function findScripts(dir, extensions) {
|
function findScripts(dir, scriptExtensions) {
|
||||||
assert(dir, g.f('cannot require directory contents without directory name'));
|
assert(dir, g.f('cannot require directory contents without directory name'));
|
||||||
|
|
||||||
var files = tryReadDir(dir);
|
var files = tryReadDir(dir);
|
||||||
extensions = extensions || _.keys(require.extensions);
|
scriptExtensions = scriptExtensions || require.extensions;
|
||||||
|
|
||||||
// sort files in lowercase alpha for linux
|
// sort files in lowercase alpha for linux
|
||||||
files.sort(function(a, b) {
|
files.sort(function(a, b) {
|
||||||
|
@ -181,9 +194,9 @@ function findScripts(dir, extensions) {
|
||||||
var filepath = path.resolve(path.join(dir, filename));
|
var filepath = path.resolve(path.join(dir, filename));
|
||||||
var stats = fs.statSync(filepath);
|
var stats = fs.statSync(filepath);
|
||||||
|
|
||||||
// only require files supported by require.extensions (.txt .md etc.)
|
// only require files supported by specified extensions
|
||||||
if (stats.isFile()) {
|
if (stats.isFile()) {
|
||||||
if (isPreferredExtension(filename))
|
if (scriptExtensions && isPreferredExtension(filename, scriptExtensions))
|
||||||
results.push(filepath);
|
results.push(filepath);
|
||||||
else
|
else
|
||||||
debug('Skipping file %s - unknown extension', filepath);
|
debug('Skipping file %s - unknown extension', filepath);
|
||||||
|
@ -204,9 +217,12 @@ function tryReadDir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildAllModelInstructions(rootDir, modelsConfig, sources,
|
function buildAllModelInstructions(rootDir, modelsConfig, sources,
|
||||||
modelDefinitions) {
|
modelDefinitions, scriptExtensions) {
|
||||||
var registry = verifyModelDefinitions(rootDir, modelDefinitions) ||
|
var registry = verifyModelDefinitions(rootDir, modelDefinitions,
|
||||||
findModelDefinitions(rootDir, sources);
|
scriptExtensions);
|
||||||
|
if (!registry) {
|
||||||
|
registry = findModelDefinitions(rootDir, sources, scriptExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
var modelNamesToBuild = addAllBaseModels(registry, Object.keys(modelsConfig));
|
var modelNamesToBuild = addAllBaseModels(registry, Object.keys(modelsConfig));
|
||||||
|
|
||||||
|
@ -287,7 +303,7 @@ function sortByInheritance(instructions) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyModelDefinitions(rootDir, modelDefinitions) {
|
function verifyModelDefinitions(rootDir, modelDefinitions, scriptExtensions) {
|
||||||
if (!modelDefinitions || modelDefinitions.length < 1) {
|
if (!modelDefinitions || modelDefinitions.length < 1) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -299,7 +315,7 @@ function verifyModelDefinitions(rootDir, modelDefinitions) {
|
||||||
definition.sourceFile = fixFileExtension(
|
definition.sourceFile = fixFileExtension(
|
||||||
fullPath,
|
fullPath,
|
||||||
tryReadDir(path.dirname(fullPath)),
|
tryReadDir(path.dirname(fullPath)),
|
||||||
true);
|
scriptExtensions);
|
||||||
if (!definition.sourceFile) {
|
if (!definition.sourceFile) {
|
||||||
debug('Model source code not found: %s - %s', definition.sourceFile);
|
debug('Model source code not found: %s - %s', definition.sourceFile);
|
||||||
}
|
}
|
||||||
|
@ -325,7 +341,7 @@ function verifyModelDefinitions(rootDir, modelDefinitions) {
|
||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findModelDefinitions(rootDir, sources) {
|
function findModelDefinitions(rootDir, sources, scriptExtensions) {
|
||||||
var registry = {};
|
var registry = {};
|
||||||
|
|
||||||
sources.forEach(function(src) {
|
sources.forEach(function(src) {
|
||||||
|
@ -343,7 +359,8 @@ function findModelDefinitions(rootDir, sources) {
|
||||||
})
|
})
|
||||||
.forEach(function(f) {
|
.forEach(function(f) {
|
||||||
var fullPath = path.resolve(srcDir, f);
|
var fullPath = path.resolve(srcDir, f);
|
||||||
var entry = loadModelDefinition(rootDir, fullPath, files);
|
var entry = loadModelDefinition(rootDir, fullPath, files,
|
||||||
|
scriptExtensions);
|
||||||
var modelName = entry.definition.name;
|
var modelName = entry.definition.name;
|
||||||
if (!modelName) {
|
if (!modelName) {
|
||||||
debug('Skipping model definition without Model name: %s',
|
debug('Skipping model definition without Model name: %s',
|
||||||
|
@ -445,13 +462,13 @@ function tryResolveAppPath(rootDir, relativePath, resolveOptions) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadModelDefinition(rootDir, jsonFile, allFiles) {
|
function loadModelDefinition(rootDir, jsonFile, allFiles, scriptExtensions) {
|
||||||
var definition = require(jsonFile);
|
var definition = require(jsonFile);
|
||||||
var basename = path.basename(jsonFile, path.extname(jsonFile));
|
var basename = path.basename(jsonFile, path.extname(jsonFile));
|
||||||
definition.name = definition.name || _.capitalize(_.camelCase(basename));
|
definition.name = definition.name || _.capitalize(_.camelCase(basename));
|
||||||
|
|
||||||
// find a matching file with a supported extension like `.js` or `.coffee`
|
// find a matching file with a supported extension like `.js` or `.coffee`
|
||||||
var sourceFile = fixFileExtension(jsonFile, allFiles, true);
|
var sourceFile = fixFileExtension(jsonFile, allFiles, scriptExtensions);
|
||||||
|
|
||||||
if (sourceFile === undefined) {
|
if (sourceFile === undefined) {
|
||||||
debug('Model source code not found: %s', sourceFile);
|
debug('Model source code not found: %s', sourceFile);
|
||||||
|
@ -644,19 +661,21 @@ function getExcludedExtensions() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPreferredExtension(filename) {
|
function isPreferredExtension(filename, includeExtensions) {
|
||||||
var includeExtensions = require.extensions;
|
assert(!!includeExtensions, '"includeExtensions" argument is required');
|
||||||
|
|
||||||
var ext = path.extname(filename);
|
var ext = path.extname(filename);
|
||||||
return (ext in includeExtensions) && !(ext in getExcludedExtensions());
|
return (ext in includeExtensions) && !(ext in getExcludedExtensions());
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixFileExtension(filepath, files, onlyScriptsExportingFunction) {
|
function fixFileExtension(filepath, files, scriptExtensions) {
|
||||||
var results = [];
|
var results = [];
|
||||||
var otherFile;
|
var otherFile;
|
||||||
|
|
||||||
/* Prefer coffee scripts over json */
|
/* Prefer coffee scripts over json */
|
||||||
if (isPreferredExtension(filepath)) return filepath;
|
if (scriptExtensions && isPreferredExtension(filepath, scriptExtensions)) {
|
||||||
|
return filepath;
|
||||||
|
}
|
||||||
|
|
||||||
var basename = path.basename(filepath, FILE_EXTENSION_JSON);
|
var basename = path.basename(filepath, FILE_EXTENSION_JSON);
|
||||||
var sourceDir = path.dirname(filepath);
|
var sourceDir = path.dirname(filepath);
|
||||||
|
@ -670,10 +689,7 @@ function fixFileExtension(filepath, files, onlyScriptsExportingFunction) {
|
||||||
|
|
||||||
if (!(otherFileExtension in getExcludedExtensions()) &&
|
if (!(otherFileExtension in getExcludedExtensions()) &&
|
||||||
path.basename(f, otherFileExtension) == basename) {
|
path.basename(f, otherFileExtension) == basename) {
|
||||||
if (!onlyScriptsExportingFunction)
|
if (!scriptExtensions || otherFileExtension in scriptExtensions) {
|
||||||
results.push(otherFile);
|
|
||||||
else if (onlyScriptsExportingFunction &&
|
|
||||||
(typeof require.extensions[otherFileExtension]) === 'function') {
|
|
||||||
results.push(otherFile);
|
results.push(otherFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -689,32 +705,33 @@ function resolveAppScriptPath(rootDir, relativePath, resolveOptions) {
|
||||||
}
|
}
|
||||||
var sourceDir = path.dirname(resolvedPath);
|
var sourceDir = path.dirname(resolvedPath);
|
||||||
var files = tryReadDir(sourceDir);
|
var files = tryReadDir(sourceDir);
|
||||||
var fixedFile = fixFileExtension(resolvedPath, files, false);
|
var fixedFile = fixFileExtension(resolvedPath, files);
|
||||||
return (fixedFile === undefined ? resolvedPath : fixedFile);
|
return (fixedFile === undefined ? resolvedPath : fixedFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildAllMixinInstructions(appRootDir, mixinDirs, mixinSources, options,
|
function buildAllMixinInstructions(appRootDir, options, mixinSources,
|
||||||
modelInstructions) {
|
scriptExtensions, modelInstructions) {
|
||||||
var extensions = _.without(_.keys(require.extensions),
|
|
||||||
_.keys(getExcludedExtensions()));
|
|
||||||
|
|
||||||
// load mixins from `options.mixins`
|
// load mixins from `options.mixins`
|
||||||
var sourceFiles = options.mixins || [];
|
var sourceFiles = options.mixins || [];
|
||||||
var instructionsFromMixins = loadMixins(sourceFiles, options);
|
var mixinDirs = options.mixinDirs || [];
|
||||||
|
var instructionsFromMixins = loadMixins(sourceFiles, options.normalization);
|
||||||
|
|
||||||
// load mixins from `options.mixinDirs`
|
// load mixins from `options.mixinDirs`
|
||||||
sourceFiles = findMixinDefinitions(appRootDir, mixinDirs, extensions);
|
sourceFiles = findMixinDefinitions(appRootDir, mixinDirs, scriptExtensions);
|
||||||
if (sourceFiles === undefined) return;
|
if (sourceFiles === undefined) return;
|
||||||
var instructionsFromMixinDirs = loadMixins(sourceFiles, options);
|
var instructionsFromMixinDirs = loadMixins(sourceFiles,
|
||||||
|
options.normalization);
|
||||||
|
|
||||||
/* If `mixinDirs` and `mixinSources` have any directories in common,
|
/* If `mixinDirs` and `mixinSources` have any directories in common,
|
||||||
* then remove the common directories from `mixinSources` */
|
* then remove the common directories from `mixinSources` */
|
||||||
mixinSources = _.difference(mixinSources, mixinDirs);
|
mixinSources = _.difference(mixinSources, mixinDirs);
|
||||||
|
|
||||||
// load mixins from `options.mixinSources`
|
// load mixins from `options.mixinSources`
|
||||||
sourceFiles = findMixinDefinitions(appRootDir, mixinSources, extensions);
|
sourceFiles = findMixinDefinitions(appRootDir, mixinSources,
|
||||||
|
scriptExtensions);
|
||||||
if (sourceFiles === undefined) return;
|
if (sourceFiles === undefined) return;
|
||||||
var instructionsFromMixinSources = loadMixins(sourceFiles, options);
|
var instructionsFromMixinSources = loadMixins(sourceFiles,
|
||||||
|
options.normalization);
|
||||||
|
|
||||||
// Fetch unique list of mixin names, used in models
|
// Fetch unique list of mixin names, used in models
|
||||||
var modelMixins = fetchMixinNamesUsedInModelInstructions(modelInstructions);
|
var modelMixins = fetchMixinNamesUsedInModelInstructions(modelInstructions);
|
||||||
|
@ -732,7 +749,7 @@ function buildAllMixinInstructions(appRootDir, mixinDirs, mixinSources, options,
|
||||||
return _.values(mixins);
|
return _.values(mixins);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findMixinDefinitions(appRootDir, sourceDirs, extensions) {
|
function findMixinDefinitions(appRootDir, sourceDirs, scriptExtensions) {
|
||||||
var files = [];
|
var files = [];
|
||||||
sourceDirs.forEach(function(dir) {
|
sourceDirs.forEach(function(dir) {
|
||||||
var path = tryResolveAppPath(appRootDir, dir);
|
var path = tryResolveAppPath(appRootDir, dir);
|
||||||
|
@ -740,12 +757,12 @@ function findMixinDefinitions(appRootDir, sourceDirs, extensions) {
|
||||||
debug('Skipping unknown module source dir %j', dir);
|
debug('Skipping unknown module source dir %j', dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
files = files.concat(findScripts(path, extensions));
|
files = files.concat(findScripts(path, scriptExtensions));
|
||||||
});
|
});
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMixins(sourceFiles, options) {
|
function loadMixins(sourceFiles, normalization) {
|
||||||
var mixinInstructions = {};
|
var mixinInstructions = {};
|
||||||
sourceFiles.forEach(function(filepath) {
|
sourceFiles.forEach(function(filepath) {
|
||||||
var dir = path.dirname(filepath);
|
var dir = path.dirname(filepath);
|
||||||
|
@ -753,7 +770,7 @@ function loadMixins(sourceFiles, options) {
|
||||||
var name = path.basename(filepath, ext);
|
var name = path.basename(filepath, ext);
|
||||||
var metafile = path.join(dir, name + FILE_EXTENSION_JSON);
|
var metafile = path.join(dir, name + FILE_EXTENSION_JSON);
|
||||||
|
|
||||||
name = normalizeMixinName(name, options);
|
name = normalizeMixinName(name, normalization);
|
||||||
var meta = {};
|
var meta = {};
|
||||||
meta.name = name;
|
meta.name = name;
|
||||||
if (utils.fileExistsSync(metafile)) {
|
if (utils.fileExistsSync(metafile)) {
|
||||||
|
@ -788,8 +805,7 @@ function filterMixinInstructionsUsingWhitelist(instructions, includeMixins) {
|
||||||
return filteredInstructions;
|
return filteredInstructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeMixinName(str, options) {
|
function normalizeMixinName(str, normalization) {
|
||||||
var normalization = options.normalization;
|
|
||||||
switch (normalization) {
|
switch (normalization) {
|
||||||
case false:
|
case false:
|
||||||
case 'none': return str;
|
case 'none': return str;
|
||||||
|
|
|
@ -299,6 +299,23 @@ describe('executor', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('searches boot file extensions specified in options.scriptExtensions',
|
||||||
|
function(done) {
|
||||||
|
var options = {
|
||||||
|
app: app,
|
||||||
|
appRootDir: path.join(__dirname, './fixtures/simple-app'),
|
||||||
|
scriptExtensions: ['.customjs', '.customjs2'],
|
||||||
|
};
|
||||||
|
boot.execute(app, boot.compile(options), function(err) {
|
||||||
|
if (err) return done(err);
|
||||||
|
expect(process.bootFlags, 'process: bootFlags').to.eql([
|
||||||
|
'customjs',
|
||||||
|
'customjs2',
|
||||||
|
]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('for mixins', function() {
|
describe('for mixins', function() {
|
||||||
var options;
|
var options;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function(app, callback) {
|
||||||
|
process.bootFlags.push('customjs');
|
||||||
|
callback();
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function(app, callback) {
|
||||||
|
process.bootFlags.push('customjs2');
|
||||||
|
callback();
|
||||||
|
};
|
Loading…
Reference in New Issue