mimicry/dependency.js

188 lines
6.7 KiB
JavaScript

(function privateDependencyClosure () {
/**
* This primitive class represents Dependency,
* just to make the work a bit more structured
* */
class Dependency {
constructor (name, contentType) {
this.name = name;
this.contentType = contentType;
}
/**
* This function goes through an array of strings and number to make sense of it
*
* @param {Array} deps - an array of strings and numbers
*
* @returns Array<Dependency>
* */
static refineDependencies (deps) {
const result = [];
const collection = Object.create(null);
for (let i = 0; i < deps.length; ++i) {
let element = deps[i];
const elementType = typeof element
if (!collection[element] && elementType === "string") {
result.push(new Dependency(element));
collection[element] = true;
} else if (result.length > 0 && elementType === "number" && ReverseType[element] !== undefined) {
let prevResult = result[result.length - 1];
if (deps[i - 1] === prevResult.name)
prevResult.contentType = element;
}
}
return result
}
/**
* Checks one type against another and writes a warning if they don't match
*
* @param {Type} original
* @param {Type} current
* @param {String} path
* */
static checkContentType (original, current, path) {
if (original !== current) {
const originalType = ReverseType[original];
const currentType = ReverseType[current];
console.warn("Mimicry error: file " + path +
" was originally requested as " + originalType +
" but next time it was requested as " + currentType +
" ignoring second request type and treating file as " + originalType
);
}
}
/**
* Refines path turning all meta information into a path to query
*
* @typedef Mimicry.Type Type
*
* @param {String} path - a source path
* @param {Type} type - type of the content
* @param {String} baseUrl - path to all project files
* @param {Map<Type, String>} types - collection of paths to specific content types
* @param {Map<String, String>} libs - collection of paths to libraries
*
* @returns {String}
* */
static refinePath (path, type, baseUrl, types, libs) {
const suffix = suffixes[type];
const typePath = types.get(type) || "";
if (!path.endsWith(suffix))
path += suffix;
switch (type) {
case Type.js:
if (path[0] === "@") {
const hops = path.split("/");
const libName = hops[0].slice(1);
let libPath = libs.get(libName);
if (libPath === undefined)
libPath = libName;
path = baseUrl + libPath + path.slice(libName.length + 1);
} else {
path = baseUrl + typePath + path;
}
break;
default:
path = baseUrl + typePath + path;
break;
}
return path;
}
/**
* @param {Array<String>} dependencies - list of module names that this module depends on
* @param {Function} [callback] - module body that will be executed as soon all dependencies are resolved
* */
static refineModuleArguments (dependencies, callback) {
let deps, body;
if (dependencies instanceof Function) {
body = dependencies;
deps = [];
} else {
deps = dependencies;
body = callback;
}
deps = this.refineDependencies(deps);
return {deps, body};
}
/**
* @param {String} href - script DOM element that launched this function
* @param {String} baseUrl - path to all project files
* @param {Map<Type, String>} types - collection of paths to specific content types
* @param {Map<String, String>} libs - collection of paths to libraries
* */
static nameFromHref (href, baseUrl, types, libs) {
const suffix = suffixes[Type.js];
const typePath = types.get(Type.js) || "";
if (href.endsWith(suffix))
href = href.slice(0, -suffix.length);
if (baseUrl.length) {
const baseIndex = href.indexOf(baseUrl);
if (baseIndex !== 0)
console.warn("Module path " + href +
" doesn't start with baseUrl " + baseUrl +
", this is probably an error");
else
href = href.slice(baseUrl.length);
}
let foundAmongLibs = false;
for (const [libName, libPath] of libs) {
const index = href.indexOf(libPath);
if (index === 0) {
href = "@" + libName + href.slice(libPath.length);
foundAmongLibs = true;
break;
}
}
if (!foundAmongLibs && typePath.length) {
const typeIndex = href.indexOf(typePath);
if (typeIndex !== 0)
console.warn("Module path " + href +
" doesn't start with a proper type path " + typePath +
", this is probably an error");
else
href = href.slice(typePath.length + 1);
}
return href;
}
static get Type () {return Type;}
static getTypeTitle (/*Type*/type) {return ReverseType[type];}
}
const Type = {
none: 0, //just to prevent implicit situations, DON'T USE IT!
js: 1,
css: 2,
json: 3,
binary: 4,
text: 5
};
const suffixes = ["", ".js", ".css", ".json", "", ""];
const ReverseType = ["None", "JavaScript", "CSS", "JSON", "Binary", "Text"];
Object.freeze(Type);
Object.freeze(suffixes);
Object.freeze(ReverseType);
if (typeof module === 'object' && module.exports)
module.exports = Dependency;
else
window.__MimicryDependency__ = Dependency;
})();