Plato on Github
Report Home
node_modules/wire/builder/cram.js
Maintainability
73.94
Lines of code
242
Difficulty
36.27
Estimated Errors
1.71
Function weight
By Complexity
By SLOC
/** @license MIT License (c) copyright B Cavalier & J Hann */ /** * wire/cram/builder plugin * Builder plugin for cram * https://github.com/cujojs/cram * * wire is part of the cujoJS family of libraries (http://cujojs.com/) * * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php */ (function(define) { define(function(require) { var when, unfold, mid, defaultModuleRegex, defaultSpecRegex, replaceIdsRegex, removeCommentsRx, splitIdsRegex; when = require('when'); unfold = require('when/unfold'); mid = require('../lib/loader/moduleId'); // default dependency regex defaultModuleRegex = /\.(module|create)$/; defaultSpecRegex = /\.(wire\.spec|wire)$/; // adapted from cram's scan function: //replaceIdsRegex = /(define)\s*\(\s*(?:\s*["']([^"']*)["']\s*,)?(?:\s*\[([^\]]+)\]\s*,)?\s*(function)?\s*(?:\(([^)]*)\))?/g; //replaceIdsRegex = /(define)\s*\(\s*(?:\s*["']([^"']*)["']\s*,)?(?:\s*\[([^\]]*)\]\s*,)?/; replaceIdsRegex = /(\bdefine)\s*\(\s*(?:\s*'([^']*)'|"([^"]*)"\s*,)?(?:\s*\[([^\]]*)\]\s*,)?/; removeCommentsRx = /\/\*[\s\S]*?\*\//g; splitIdsRegex = /\s*,\s*/; return { normalize: normalize, compile: compile }; function normalize(resourceId, toAbsId) { return resourceId ? toAbsId(resourceId.split("!")[0]) : resourceId; } function compile(wireId, resourceId, require, io, config) { // Track all modules seen in wire spec, so we only include them once var specIds, defines, seenModules, childSpecRegex, moduleRegex; defines = []; seenModules = {}; moduleRegex = defaultModuleRegex; childSpecRegex = defaultSpecRegex; // Get config values if(config) { if(config.moduleRegex) moduleRegex = new RegExp(config.moduleRegex); if(config.childSpecRegex) childSpecRegex = new RegExp(config.childSpecRegex); } // Grab the spec module id, *or comma separated list of spec module ids* // Split in case it's a comma separated list of spec ids specIds = resourceId.split(splitIdsRegex); return when.map(specIds, function(specId) { return processSpec(specId); }).then(write, io.error); // For each spec id, add the spec itself as a dependency, and then // scan the spec contents to find all modules that it needs (e.g. // "module" and "create") function processSpec(specId) { var dependencies, ids; dependencies = []; ids = [specId]; _addDep(wireId); return unfold(fetchNextSpec, endOfList, scanSpec, ids) .then(function() { return generateDefine(specId, dependencies); } ); function fetchNextSpec() { var id = ids.shift(); return when.promise(function(resolve, reject) { require( [id], function(spec) { resolve([{ spec: spec, id: id }, ids]); }, reject ); }); } function _addDep(moduleId) { if(!(moduleId in seenModules)) { dependencies.push(moduleId); seenModules[moduleId] = moduleId; } } function scanSpec(specDescriptor) { var spec = specDescriptor.spec; scanPlugins(spec); scanObj(spec); function resolveId(moduleId) { return mid.resolve(specDescriptor.id, moduleId) } function scanObj(obj, path) { // Scan all keys. This might be the spec itself, // or any sub-object-literal in the spec. for (var name in obj) { scanItem(obj[name], createPath(path, name)); } } function scanItem(it, path) { // Determine the kind of thing we're looking at // 1. If it's a string, and the key is module or create, then assume it // is a moduleId, and add it as a dependency. // 2. If it's an object or an array, scan it recursively // 3. If it's a wire spec, add it to the list of spec ids if (isSpec(path) && typeof it === 'string') { addSpec(it); } else if (isDep(path) && typeof it === 'string') { // Get module def addDep(it); } else if (isStrictlyObject(it)) { // Descend into subscope scanObj(it, path); } else if (Array.isArray(it)) { // Descend into array var arrayPath = path + '[]'; it.forEach(function(arrayItem) { scanItem(arrayItem, arrayPath); }); } } function scanPlugins(spec) { var plugins = spec.$plugins || spec.plugins; if(Array.isArray(plugins)) { plugins.forEach(addPlugin); } else if(typeof plugins === 'object') { Object.keys(plugins).forEach(function(key) { addPlugin(plugins[key]); }); } } function addPlugin(plugin) { if(typeof plugin === 'string') { addDep(plugin); } else if(typeof plugin === 'object' && plugin.module) { addDep(plugin.module); } } function addDep(moduleId) { _addDep(resolveId(moduleId)); } function addSpec(specId) { specId = resolveId(specId); if(!(specId in seenModules)) { ids.push(specId); } _addDep(specId); } } } function generateDefine(specId, dependencies) { var dfd, buffer; dfd = when.defer(); io.read(ensureExtension(specId, 'js'), function(specText) { buffer = injectIds(specText, specId, dependencies); defines.push(buffer); dfd.resolve(); }, dfd.reject); return dfd.promise; } function write() { // protect against prior code that may have omitted a semi-colon io.write('\n;' + defines.join('\n')); } function isDep(path) { return moduleRegex.test(path); } function isSpec(path) { return childSpecRegex.test(path); } } function createPath(path, name) { return path ? (path + '.' + name) : name } function isStrictlyObject(it) { return (it && Object.prototype.toString.call(it) == '[object Object]'); } function ensureExtension(id, ext) { return id.lastIndexOf('.') <= id.lastIndexOf('/') ? id + '.' + ext : id; } function injectIds(moduleText, absId, moduleIds) { var replaced, newText; // note: replaceIdsRegex removes commas, parens, and brackets newText = moduleText.replace(removeCommentsRx, '').replace(replaceIdsRegex, function (m, def, mid1, mid2, depIds) { replaced = true; // merge deps, but not args since they're not referenced in module if(depIds) { moduleIds = depIds.split(splitIdsRegex).concat(moduleIds); } moduleIds = '[' + moduleIds.map(quoted).join(', ') + '], '; return def + '(' + quoted(absId) + ', ' + moduleIds; }); if (!replaced) { throw new Error('Unable to parse AMD define() in ' + absId); } return newText; } function quoted(id) { return '"' + id + '"'; } function endOfList(ids) { return !ids.length; } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));