UNPKG

broccoli-babel-transpiler

Version:

A Broccoli plugin which transpile ES6 to readable ES5 by using babel.

138 lines (109 loc) 4.47 kB
'use strict'; const stringify = require('json-stable-stringify'); const crypto = require('crypto'); const hashForDep = require('hash-for-dep'); const path = require('path'); const fs = require('fs'); module.exports = function optionsHash(options, console) { const hash = { plugins: [] }; for (let key in options) { const value = options[key]; hash[key] = (typeof value === 'function') ? (value + '') : value; } const babelPlugins = options.babel.plugins; if (babelPlugins) { if (!Array.isArray(babelPlugins)) { throw new TypeError('broccoli-babel-transpiler: babel options.babel.plugins must either be omitted or an array'); } const cacheableItems = []; for (let i = 0; i < babelPlugins.length; i++) { const plugin = babelPlugins[i]; if (isAbsolutePathPlugin(plugin)) { const pluginPath = typeof plugin === 'string' ? plugin : plugin[0]; cacheableItems.push(hashForDep('.', modulePath(pluginPath))) if (typeof plugin === 'string') { // do nothing } else if (Array.isArray(plugin)) { plugin.slice(1).forEach(item => cacheableItems.push(item)); } else { throw new TypeError('Expected string or array but got: ' + typeof plugin); } } else { cacheableItems.push(plugin); } } for (let i = 0; i < cacheableItems.length; i++) { const item = cacheableItems[i]; const type = typeof item; if (Array.isArray(item)) { item.forEach(part => cacheableItems.push(part)); } else if (item === null) { hash.plugins.push(item); } else if (type === 'function' || type === 'object') { const augmentsCacheKey = typeof item.cacheKey === 'function'; const providesBaseDir = typeof item.baseDir === 'function'; if (augmentsCacheKey) { hash.plugins.push(item.cacheKey()); } if (providesBaseDir) { hash.plugins.push(hashForDep(item.baseDir())); } if (!providesBaseDir && !augmentsCacheKey) { if (type === 'object') { // iterate all keys in the item and push them into the cache Object.keys(item).forEach(key => { cacheableItems.push(key); cacheableItems.push(item[key]); }); } else { // prevent caching completely if the plugin doesn't provide baseDir // we cannot ensure that we aren't causing invalid caching pain... console.warn('broccoli-babel-transpiler is opting out of caching due to a plugin that does not provide a caching strategy: `' + item + '`.'); // so simply provide a unstable hash value and skip serialization return crypto.createHash('md5').update((new Date).getTime() + '|' + Math.random(), 'utf8').digest('hex'); } } } else if (type !== 'object') { // handle native strings, numbers (which can JSON.stringify properly) hash.plugins.push(item); } else { throw new Error('broccoli-babel-transpiler: unknown babel options value'); } } } return crypto.createHash('md5').update(stringify(hash), 'utf8').digest('hex'); } function isAbsolutePath(maybePath) { return typeof maybePath === 'string' && path.isAbsolute(maybePath); } module.exports.isAbsolutePathPlugin = isAbsolutePathPlugin; function isAbsolutePathPlugin(maybePlugin) { if (isAbsolutePath(maybePlugin)) { return true; } if (Array.isArray(maybePlugin) && isAbsolutePath(maybePlugin[0])) { return true; } return false } const MODULE_NAME_FROM_PATH_CACHE = Object.create(null); const THROW_ON_ACCESS = function() { } function couldNotInferModuleFrom(from) { throw new Error('Could not infer module from: `' + from + '`') } module.exports.modulePath = modulePath; function modulePath(filePath) { const originalFilePath = filePath; const cachedValue = MODULE_NAME_FROM_PATH_CACHE[originalFilePath]; if (cachedValue === THROW_ON_ACCESS) { couldNotInferModuleFrom(originalFilePath); } else if (typeof cachedValue === 'string') { return cachedValue; } while (filePath !== '/') { const test = filePath + '/package.json'; if (fs.existsSync(test)) { MODULE_NAME_FROM_PATH_CACHE[originalFilePath] = filePath; return filePath; } filePath = path.dirname(filePath); } MODULE_NAME_FROM_PATH_CACHE[originalFilePath] = THROW_ON_ACCESS; couldNotInferModuleFrom(originalFilePath); }