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.

359 lines (299 loc) 13.6 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", ['raptor'], function(raptor, require, exports, module) { "use strict"; var forEachEntry = raptor.forEachEntry, mappings = {}, logger = require('raptor/logging').logger('packaging-server'), packageManifests = {}, enabledExtensions = null, dependencyClasses = {}, discoveryComplete = false, searchPathListenerHandle = null, ExtensionCollection = require('raptor/packaging/ExtensionCollection'), PackageManifest = require('raptor/packaging/PackageManifest'), PackageLoader = require('raptor/packaging/PackageLoader'), getEnabledExtensions = function() { if (!enabledExtensions) { enabledExtensions = new ExtensionCollection(); } return enabledExtensions; }, createModuleManifestForResource = function(resource) { var manifest = require('raptor/packaging').createPackageManifest(); manifest.setPackageResource(resource); manifest.setDependencies([{ path: resource.getName() }]); return manifest; }, getModuleDirPath = function(id) { return '/' + id.replace(/\./g, '/'); }, topLevelManifests = null; function getPreferredSearchPath(path) { if (path.charAt(0) === '/') { path = path.substring(1); } var firstPartEnd = path.indexOf('/'); var modulePrefix = firstPartEnd === -1 ? path : path.substring(0, firstPartEnd); return raptor.getModuleSearchPath(modulePrefix); } return { ExtensionCollection: ExtensionCollection, createExtensionCollection: function(enabledExtensions) { return new ExtensionCollection(enabledExtensions); }, isExtensionCollection: function(extensions) { return extensions instanceof ExtensionCollection; }, enableExtension: function(extensionName) { getEnabledExtensions().add(extensionName); }, getEnabledExtensions: function() { return getEnabledExtensions(); }, /** * * @param resourcePath {String|packaging-PackageManifest} */ load: function(resourcePath) { PackageLoader.instance.load(resourcePath, {enabledExtensions: getEnabledExtensions()}); }, _watchResourceSearchPath: function() { if (!searchPathListenerHandle) { searchPathListenerHandle = require('raptor/resources').getSearchPath().subscribe("modified", function() { discoveryComplete = false; this._doDiscovery(); //If the search path is modified then rediscover the }, this); } }, _doDiscovery: function() { if (discoveryComplete) { return; } try { discoveryComplete = true; topLevelManifests = []; require('raptor/resources').forEach('/package.json', function(manifestResource) { var manifest = this.getPackageManifest(manifestResource); topLevelManifests.push(manifest); var manifestModuleMappings = manifest.getRaptorProp("module-mappings"); if (manifestModuleMappings) { raptor.extend(mappings, manifestModuleMappings); } var manifestDependencyHandlers = manifest.getRaptorProp("dependency-types"); if (manifestDependencyHandlers) { forEachEntry(manifestDependencyHandlers, function(type, handlerInfo) { if (handlerInfo.path) { require('raptor/runtime').evaluateResource(handlerInfo.path); } try { var Dependency = require(typeof handlerInfo === 'string' ? handlerInfo : handlerInfo["class"]); this.registerDependencyClass(type, Dependency); } catch(e) { logger.error('Unable to register dependency type of "' + type + '". Exception: ' + e, e); } }, this); } }, this); } finally { this._watchResourceSearchPath(); } }, registerDependencyClass: function(type, dependencyClass) { dependencyClasses[type] = dependencyClass; }, isKnownDependencyType: function(type) { this._doDiscovery(); return !!dependencyClasses[type]; }, /** * @return the dependency class (constructor function) for the given type * or undefined if there is no dependency class associated with the given type */ getDependencyClass: function(type) { this._doDiscovery(); return dependencyClasses[type]; }, removePackageManifestFromCache: function(manifest) { delete packageManifests[manifest.getURL()]; }, isPackageManifest: function(o) { return o instanceof PackageManifest; }, createPackageManifest: function(loadedManifest, packageResource) { var manifest = new PackageManifest(); if (packageResource) { manifest.setPackageResource(packageResource); } if (loadedManifest) { raptor.extend(manifest, loadedManifest); if (loadedManifest.hasOwnProperty("raptor")) { var raptorObj = loadedManifest.raptor; if (raptorObj) { manifest.setDependencies(raptorObj.dependencies); manifest.setExtensions(raptorObj.extensions); } } else if (Array.isArray(loadedManifest.includes) || Array.isArray(loadedManifest.dependencies)) { manifest.setDependencies(loadedManifest.includes || loadedManifest.dependencies); manifest.setExtensions(loadedManifest.extensions); } else { // clear out the dependencies and extensions becuase the // manifest does not belong to a raptor module manifest.setDependencies(null); manifest.setExtensions(null); } } return manifest; }, getPackageManifestResource: function(resourcePath) { var resources = require('raptor/resources'); if (resources.isResource(resourcePath)) { return resourcePath; } else { // We support an optimization to map a module prefix to a search path so that // we don't have to serach every single search path entry for the module var searchPath = getPreferredSearchPath(resourcePath); return resources.findResourcePreferredSearchPath(resourcePath, searchPath); } }, /** * * @param resourcePath * @param exists if the value of this argument is true then the resource existance check will be skipped * @returns */ getPackageManifest: function(resourcePath, exists) { var packageResource = this.getPackageManifestResource(resourcePath); if (!packageResource || (exists !== true) && !packageResource.exists()) { return null; } var manifest = packageManifests[packageResource.getURL()]; if (manifest === undefined) { var packageJson = packageResource.readAsString("UTF-8"), loadedManifest; try { loadedManifest = JSON.parse(packageJson); } catch(e) { throw raptor.createError(new Error('Unable to parse module manifest at path "' + packageResource.getURL() + '". Exception: ' + e + '\n\nJSON:\n' + packageJson), e); } manifest = this.createPackageManifest(loadedManifest, packageResource); packageManifests[packageResource.getURL()] = manifest; } return manifest; }, /** * * @param callback {Function} * @param thisObj {Object} */ forEachTopLevelPackageManifest: function(callback, thisObj) { this._doDiscovery(); topLevelManifests.forEach(callback, thisObj); }, /** * @return the package manifest resource associated with the given module name or null * (a non-null value also guarantees that the returned resource exists) */ getPackageManifestResourceForModule: function(name) { this._doDiscovery(); var target = mappings[name], packaging = this, resource; if (target) { if (require('raptor/strings').endsWith(target, "package.json")) { resource = packaging.getPackageManifestResource(target); return resource.exists() ? resource : null; } else { return packaging.getPackageManifestResourceForModule(target); } } var dir = getModuleDirPath(name); resource = packaging.getPackageManifestResource(dir + "/package.json"); if (resource.exists()) { return resource; } resource = packaging.getPackageManifestResource(dir + "-package.json"); if (resource.exists()) { return resource; } /* * Sample module name: * my-module.sub-module */ if (!name.endsWith('.js') && !name.endsWith('/js')) { var resources = require('raptor/resources'); var basePath = '/' + name.replace(/\./g, '/'); //sample basePath: /my-module/sub-module var resourcePath = basePath + '.js'; //sample resourcePath: /my-module/sub-module.js var searchPath = getPreferredSearchPath(name); var manifest; resource = resources.findResourcePreferredSearchPath(resourcePath, searchPath); if (resource && resource.exists()) { manifest = createModuleManifestForResource(resource); // cache the "fake" package manifest that we created packageManifests[resource.getURL()] = manifest; return resource; } var lastSlash = basePath.lastIndexOf('/'); if (lastSlash !== -1) { resourcePath = basePath + '/' + basePath.substring(lastSlash+1) + ".js"; //sample resourcePath: /my-module/sub-module/sub-module.js resource = resources.findResourcePreferredSearchPath(resourcePath, searchPath); if (resource.exists()) { manifest = createModuleManifestForResource(resource); // cache the "fake" package manifest that we created packageManifests[resource.getURL()] = manifest; return resource; } } } // if we didn't return earlier then resource was not found return null; }, getModuleManifest: function(name) { this._doDiscovery(); var resource = this.getPackageManifestResourceForModule(name); if (!resource) { return null; } var manifest = this.getPackageManifest(resource, true /* exists */); if (manifest) { manifest.setName(name); } return manifest; }, clearCache: function() { packageManifests = {}; }, createDependencyWalker: function() { var DependencyWalker = require('raptor/packaging/DependencyWalker'); return new DependencyWalker(); }, createDependency: PackageManifest.createDependency }; });