confinode
Version:
Node application configuration reader
140 lines • 5.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const loaders_1 = require("./loaders");
/**
* Indicate if the description is a loaded loader.
*
* @param description - The description to check.
* @returns True if loaded loader.
*/
function isLoadedLoader(description) {
return 'loader__' in description;
}
/**
* Asserts that the description contains a loaded loader.
*
* @param description - The description to test.
*/
function assertIsLoadedLoader(description) {
/* istanbul ignore if */
if (!isLoadedLoader(description)) {
throw new Error('Description should contain a loaded loader');
}
}
/**
* Try to resolve the module.
*
* @param moduleName - The name of the module.
* @param paths - The paths where modules are searched.
* @returns The path of the file to load.
*/
function searchModulePath(moduleName, paths) {
try {
return require.resolve(moduleName, { paths });
}
catch (_a) {
return undefined;
}
}
/**
* Used to detect where there are no available loaders.
*/
class NoAvailableLoaderError extends Error {
}
/**
* The loader manager is responsible of selecting the appropriate loader for each file.
*/
class LoaderManager {
/**
* Create the loader manager.
*
* @param applicationName - The application name, used to name custom loaders.
* @param customLoaders - The custom loaders which will be added/replace the provided ones.
*/
constructor(applicationName, customLoaders) {
const [customDescription, customExtensionsLoaders] = loaders_1.analyzeLoaders(customLoaders, applicationName + '#');
this.descriptions = { ...loaders_1.loaderDescriptions, ...customDescription };
this.extensionsLoaders = { ...loaders_1.extensionsLoaders, ...customExtensionsLoaders };
this.availableTypes = Object.keys(this.extensionsLoaders).sort((a, b) => b.length - a.length);
}
/**
* Get the loader for the given file name.
*
* @param paths - The extra paths where modules are searched.
* @param syncOnly - Do not use loaders if they cannot load synchronously.
* @param fileName - The (base) name of the file to search.
* @param extension - The extension of the file if already known.
* @returns A generator of the most appropriate loader and its name, or undefined if none found.
*/
getLoaders(paths, syncOnly, fileName, extension) {
const loaderGenerator = this.createLoaders(paths, syncOnly, this.availableTypes
.filter(availableType => extension
? availableType === extension
: fileName.length > availableType.length + 1 && fileName.endsWith('.' + availableType))
.reduce((previous, type) => [...previous, ...this.extensionsLoaders[type]], [])
.filter(utils_1.unique)
.map(loaderName => [loaderName, this.descriptions[loaderName]]));
try {
loaderGenerator.next();
return loaderGenerator;
}
catch (e) {
/* istanbul ignore next */
if (e instanceof NoAvailableLoaderError) {
return undefined;
}
else {
throw e;
}
}
}
/**
* Create an iterator over the loaders. Throws if no available iterator found.
*
* @param paths - The extra paths where modules are searched.
* @param syncOnly - Do not use loaders if they cannot load synchronously.
* @param matching - The loaders matching the given file name.
* @returns The most appropriate loader and its name.
*/
*createLoaders(paths, syncOnly, matching) {
let lastLoader;
let nextLoader;
for (const [loaderName, description] of matching) {
let path;
if (!isLoadedLoader(description) && description.module) {
path = searchModulePath(description.module, paths);
}
if (isLoadedLoader(description) || !description.module || !!path) {
if (!isLoadedLoader(description)) {
// Load the loader and update the object
const required = path ? require(path) : undefined;
this.descriptions[loaderName] = { loader__: new description.Loader(required) };
}
const loadedLoader = this.descriptions[loaderName];
assertIsLoadedLoader(loadedLoader);
if (!syncOnly || loadedLoader.loader__.syncLoad) {
nextLoader = [loadedLoader.loader__, loaderName];
}
}
if (nextLoader) {
if (!lastLoader) {
yield nextLoader; // Only for the first call
}
else {
yield lastLoader;
}
lastLoader = nextLoader;
nextLoader = undefined;
}
}
if (lastLoader) {
return lastLoader;
}
else {
throw new NoAvailableLoaderError('No available loader');
}
}
}
exports.default = LoaderManager;
//# sourceMappingURL=LoaderManager.js.map