UNPKG

cdnjs

Version:

Search and URL retrieval from cdnjs

181 lines (161 loc) 4.97 kB
'use strict'; var request = require('request'); var moment = require('moment'); var transform = require('cdnjs-transform'); // Search methods (return array) var searchBy = function (key, term, array) { var matches = []; array.some(function (item) { if (item[key]) { if ((''+item[key]).toLowerCase().indexOf(term) !== -1) { matches.push(item); } } }); return matches; }; var searchByName = searchBy.bind(null, 'name'); // Also possible: // var searchByFilename = searchBy.bind(null, 'filename'); // var searchByDescription = searchBy.bind(null, 'description'); // Find methods (returns object or false) var findBy = function (key, term, array) { var match; array.some(function (item) { return item[key] && item[key] === term && (match = item) && true; }); return match; }; var findByName = findBy.bind(null, 'name'); // Also possible: // var findByFilename = findBy.bind(null, 'filename'); // var findByDescription = findBy.bind(null, 'description'); var toggleExtension = function (name) { var endsWithJS = /\.js$/; if (endsWithJS.test(name)) { name = name.replace(endsWithJS, ''); } else { name += '.js'; } return name; }; // The main cdnjs object var cdnjs = { urls: { packages: 'https://cdnjs.com/packages.json', base: '//cdnjs.cloudflare.com/ajax/libs/' }, /** * Build a cdnjs URL for the given package */ buildUrl: function (pkg) { var base = this.urls.base; return base + [pkg.name, pkg.version, pkg.filename || pkg.name].join('/'); }, /** * Build a usable package object with versions */ buildPackage: function (pkg) { return { name: pkg.name, url: this.buildUrl({ name: pkg.root, version: pkg.version, filename: pkg.files.minified }), versions: pkg.versions.reduce(function (memo, version) { memo[version] = this.buildUrl({ name: pkg.root, version: version, filename: pkg.files.minified }); return memo; }.bind(this), {}) }; }, /** * Extract package name and version from search term */ extractTerm: function (term) { var segments = term.split('@'); return { name: segments[0], version: segments[1] }; }, /** * Get the correct version for a given package */ getVersion: function (version, pkg) { if (!version) { return pkg; } if (pkg.url.indexOf(version) !== -1) { return pkg; } if (!pkg.versions[version]) { return pkg; } pkg.url = pkg.versions[version]; pkg.name = pkg.name + '@' + version; return pkg; }, /** * Cached list of packages * Why is this not cached to a file? Becuase the global tool should always go * looking properly, but a module using cdnjs (like an API) will keep it in * memory so it needs recaching after 24 hours. */ cache: null, /** * Grab the packages from the local cache, or cdnjs. */ packages: function (cb) { // If we've got the packages cached use them, but only if it's not expired. if (this.cache && this.cache.packages) { if (moment().isBefore(this.cache.expires)) { return cb(null, this.cache.packages, true); } } // Grab some JSON from the cdnjs list request .get({ url: this.urls.packages, json:true }, function (err, res, body) { if (err) { return cb(err); } // The wrong thing came back, gtfo if (!(body && body.packages)) { return cb(null, []); } var data = transform(body.packages); // Cache the good stuff, and set and expiry time this.cache = { packages: data, expires: moment().add('hours', 24) }; // Transform the packages into a useful form and send on back return cb(null, data); }.bind(this)); }, /** * Search the packages list for an identifier. Loosey-goosey. */ search: function (term, cb) { term = this.extractTerm(term); this.packages(function (err, packages) { if (err) { return cb(err); } // Loosely search the names of the packages, then trasform them into a // usable format. var results = searchByName(term.name, packages).map(this.buildPackage.bind(this)); if (!results.length) { return cb(new Error("No matching packages found.")); } return cb(null, results); }.bind(this)); }, /** * Get a URL for an exact identifier match. */ url: function (term, cb) { term = this.extractTerm(term); this.packages(function (err, packages) { if (err) { return cb(err); } var pkg = findByName(term.name, packages); if (!pkg) { pkg = findByName(toggleExtension(term.name), packages); } if (!pkg) { return cb(new Error("No such package found.")); } var version = this.getVersion(term.version, this.buildPackage(pkg)); return cb(null, version); }.bind(this)); } }; // Export the API module.exports = cdnjs;