UNPKG

raptor

Version:

RaptorJS provides an AMD module loader that works in Node, Rhino and the web browser. It also includes various sub-modules to support building optimized web applications.

566 lines (461 loc) 20 kB
/* * Copyright 2011 eBay Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ define("raptor/packaging/PackageManifest", ['raptor'], function(raptor, require, exports, module) { "use strict"; /** * @parent packaging_Server */ var forEach = raptor.forEach, forEachEntry = raptor.forEachEntry, ExtensionCollection = require('raptor/packaging/ExtensionCollection'), nextId = 0, _packaging; function DependencyError() { Error.apply(this, arguments); } DependencyError.prototype = new Error(); // This method is necessary so that we can correctly infer the type of dependency represented by // a path such as "SomeFile.i18n.json". // In this example, this allows both "i18n.json" and "json" to be registered types. var inferDependencyTypeFromPath = function(dependencyConfig, packaging) { // Find the type from the longest matching file extension. // For example if we are trying to infer the type of "jquery-1.8.3.js" then we will try: // a) "8.3.js" // b) "3.js" // c) "js" var path = dependencyConfig.path, lastSlash = path.lastIndexOf('/'), dotPos; if (lastSlash === -1) { // there is no slash in the path so we can use the first dot position dotPos = path.indexOf('.'); } else { // there is a slash in the path so use the first dot position after the slash dotPos = path.indexOf('.', lastSlash+1); } if (dotPos === -1) { // assume dependency is a module since the path does not have a fileextension dependencyConfig.type = 'module'; dependencyConfig.name = path; return; } var type; do { type = path.substring(dotPos + 1); if (packaging.isKnownDependencyType(type)) { dependencyConfig.type = type; return; } // move to the next dot position dotPos = path.indexOf('.', dotPos+1); } while(dotPos !== -1); }; var normalizeDependencyConfig = function(dependencyConfig) { // Cache reference to packaging module the first time we reference it var packaging = _packaging || (_packaging = require('raptor/packaging')); if (typeof dependencyConfig === 'string') { dependencyConfig = { path: dependencyConfig }; } if (!dependencyConfig.type) { // the dependency doesn't have a type so try to infer it from the path if (dependencyConfig.path) { inferDependencyTypeFromPath(dependencyConfig, packaging); } else if (dependencyConfig.hasOwnProperty('module')) { dependencyConfig.type = "module"; dependencyConfig.name = dependencyConfig.module; delete dependencyConfig.module; } else if (dependencyConfig.hasOwnProperty('package')) { dependencyConfig.type = "package"; dependencyConfig.path = dependencyConfig['package']; delete dependencyConfig['package']; } } return dependencyConfig; }; var createDependency = function(dependencyConfig, manifest) { if (dependencyConfig.__dependency) { // dependency config is already an instance of Dependency return dependencyConfig; } // The dependency configuration allows variations for defining equivalent dependencies so // we need to normalize those variations dependencyConfig = normalizeDependencyConfig(dependencyConfig); // Cache reference to packaging module the first time we reference it var packaging = _packaging || (_packaging = require('raptor/packaging')); var DependencyClass = packaging.getDependencyClass(dependencyConfig.type); if (!DependencyClass) { throw raptor.createError(new Error('Unable to load dependency "' + JSON.stringify(dependencyConfig) + '"' + (manifest ? ' in "' + manifest.getURL() + '"' : '') + '. Dependency class not found for dependency of type "' + dependencyConfig.type + '"')); } delete dependencyConfig.toString; var dependency = new DependencyClass(); raptor.extend(dependency, dependencyConfig); if (manifest) { dependency.setParentManifest(manifest); } // give the dependence a chance to do some post-construction initialization if (dependency.initialize) { dependency.initialize(); } return dependency; }; /** * Perform an in-place replacement of glob patterns with glob instances. * A glob is an instance of Minimatch. */ function convertGlobPatternsToGlobs(patterns, cache, minimatch) { for (var i = 0; i < patterns.length; i++) { var globPattern = patterns[i], mm = cache.get(globPattern); if (!mm) { mm = new minimatch.Minimatch(globPattern); cache.put(globPattern, mm); } patterns[i] = mm; } } function addDependency(dependency, target, manifest) { if (dependency.type === 'glob') { if (dependency.include !== undefined) { var minimatch = require('minimatch'); var cache = require('raptor/caching').getDefaultProvider().getCache('glob'); // always work with arrays for convenience var includes = Array.isArray(dependency.include) ? dependency.include : [dependency.include], excludes; convertGlobPatternsToGlobs(includes, cache, minimatch); if (dependency.exclude) { excludes = Array.isArray(dependency.exclude) ? dependency.exclude : [dependency.exclude]; convertGlobPatternsToGlobs(excludes, cache, minimatch); } manifest.getDirectoryResource().forEachChild(function(childResource) { var name = childResource.getName(); var i; if (name.endsWith('package.json')) { // Always skip package.json files return; } if (excludes) { for (i = 0; i < excludes.length; i++) { if (excludes[i].match(name)) { return; } } } var match = false; for (i = 0; i < includes.length; i++) { if (includes[i].match(name)) { match = true; break; } } if (!match) { return; } var dependency = { path: name }; // The file resource is part of the package target.push(createDependency(name, manifest)); }); } return; } else if (typeof dependency === 'object') { var includePattern = dependency['include-pattern']; var excludePattern = dependency['exclude-pattern']; var extensionPattern = dependency['extension-pattern']; if (includePattern || excludePattern) { if (includePattern) { includePattern = new RegExp(includePattern); } if (excludePattern) { excludePattern = new RegExp(excludePattern); } if (extensionPattern) { extensionPattern = new RegExp(extensionPattern); } // The dependency is file pattern that will // potentially match multiple dependencies var dirResource = manifest.getDirectoryResource(); dirResource.forEachChild(function(childResource) { if (!childResource.isFile()) { return; } var name = childResource.getName(); if (name.endsWith('package.json')) { // Always skip package.json files return; } if (excludePattern && excludePattern.test(name)) { // Skip the exclude file return; } if (includePattern && !includePattern.test(name)) { // The file does not match the include test return; } var dependency = { path: name }; if (extensionPattern) { // See if there is an extension embedded // within the filename var matches = name.match(extensionPattern); if (matches && matches.length > 1) { dependency.extension = matches[1]; } } // The file resource is part of the package target.push(createDependency(name, manifest)); }); return; } } target.push(createDependency(dependency, manifest)); } var PackageManifest = function() { this.dependencies = []; this.extensions = []; this.packageResource = null; this._isPackageManifest = true; this.searchPathEntry = null; this._dirResource = undefined; }; PackageManifest.createDependency = createDependency; PackageManifest.normalizeDependencyConfig = normalizeDependencyConfig; PackageManifest.isPackageManifest = function(packageManifest) { return packageManifest._isPackageManifest; }; PackageManifest.getResourceKey = function(resource) { return resource.getURL(); }; PackageManifest.prototype = { getDirectoryResource: function() { if (this._dirResource === undefined && this.packageResource) { if (this.packageResource.isDirectory()) { this._dirResource = this.packageResource; } else { this._dirResource = this.packageResource.getParent(); } } return this._dirResource; }, setPackageResource: function(packageResource) { this.packageResource = packageResource; this._dirResource = undefined; }, getDependencies: function() { return this.dependencies || []; }, getExtensions: function() { return this.extensions || []; }, setDependencies: function(dependencies) { this.dependencies = []; if (!dependencies || dependencies.length === 0) { return; } forEach(dependencies, function(dependency, i) { addDependency(dependency, this.dependencies, this); }, this); }, getKey: function() { if (this.packageResource) { return PackageManifest.getResourceKey(this.packageResource); } else { return this.key || (this.key = nextId++); } }, setExtensions: function(extensions) { if (!extensions || extensions.length === 0) { this.extensions = []; return; } if (!Array.isArray(extensions)) { this.extensions = []; //Convert the extensions to an ordered array forEachEntry(extensions, function(name, extension) { extension.name = name; this.extensions.push(extension); }, this); this.extensions.sort(function(a,b) { a = a.name; b = b.name; if (a === b) { return 0; } else if (a == null) { return -1; } else if (b == null) { return 1; } else { return a < b ? -1 : (a > b ? 1 : 0); } }); } else { this.extensions = extensions; } forEach(this.extensions, function(extension) { var outputDependencies = []; var dependencies = extension.dependencies || extension.includes; forEach(dependencies, function(dependency, i) { addDependency(dependency, outputDependencies, this); }, this); if (extension.condition) { extension.condition = eval("(function(extensions) { return " + extension.condition + ";})"); } extension.dependencies = outputDependencies; }, this); }, addDependency: function(dependencyDef) { addDependency(dependencyDef, this.dependencies, this); }, /** * */ getPackageResource: function() { return this.packageResource; }, getURL: function() { return this.packageResource ? this.packageResource.getURL() : null; }, getPath: function() { return this.packageResource.getPath(); }, /** * Returns the search path entry where the package.json resource was found. * * @returns {raptor/resources/SearchPathEntry} The search path entry where the package.json resource was found. */ getSearchPathEntry: function() { return this.packageResource ? this.packageResource.getSearchPathEntry() : null; }, /** * * @returns */ getName: function() { return this.name; }, setName: function(name) { this.name = name; }, /** */ toString: function() { return '[Package manifest: ' + this.getName() + ']'; }, resolveResource: function(relPath) { var resource = require('raptor/resources').resolveResource(this.getPackageResource(), relPath); return resource; }, load: function() { require('raptor/packaging').load(this); }, getRaptorProp: function(name) { var raptorObj = this.raptor; return raptorObj ? raptorObj[name] : null; }, /** * * @param options * @returns */ forEachDependency: function(options) { if (typeof options === 'function') { options = { callback: arguments[0], thisObj: arguments[1] }; if (arguments[2]) { raptor.extend(options, arguments[2]); } } var _this = this; if (!options) { options = {}; } var enabledExtensions = options.enabledExtensions; if (enabledExtensions === undefined) { enabledExtensions = require('raptor/packaging').getEnabledExtensions(); } else { if (!(enabledExtensions instanceof ExtensionCollection)) { enabledExtensions = new ExtensionCollection(enabledExtensions); } } var dependencyFilter = options.dependencyFilter, callback = options.callback, thisObj = options.thisObj, _isExtensionEnabled = function(extensionName) { if (enabledExtensions) { var extensionParts = extensionName.split(/[,|]/), i=0, len = extensionParts.length; for (; i<len; i++) { if (extensionParts[i] === '') { continue; //Dependency extensions with an empty string } if (!enabledExtensions.contains(extensionParts[i])) { return false; //Skip this extension if it is filtered out } } } return true; }; var _handleDependencies = function(dependencies, extension) { forEach(dependencies, function(dependency) { if (dependency.extension && !_isExtensionEnabled(dependency.extension)) { return; } if (dependencyFilter && !dependencyFilter.call(thisObj, dependency.type, dependency)) { return; } callback.call(thisObj, dependency.type, dependency, extension); }); }; if (this.dependencies) { _handleDependencies(this.dependencies, null); //Only process the regular dependencies if they are not filtered out } if (this.extensions) { forEach(this.extensions, function(extensionDef) { var extensionName = extensionDef.name; if (extensionDef.condition) { if (!enabledExtensions) { enabledExtensions = new ExtensionCollection(); } if (!extensionDef.condition(enabledExtensions)) { return; } } else if (!_isExtensionEnabled(extensionName)) { return; } _handleDependencies(extensionDef.dependencies, extensionName); }, this); } } }; return PackageManifest; });