twreporter-react
Version:
React-Redux site for The Reporter Foundation in Taiwan
292 lines (245 loc) • 7.83 kB
JavaScript
import path from 'path'
import fs from 'fs'
import require_hacker from 'require-hacker'
import { is_object, exists, starts_with } from './helpers'
// returns a stub for webpack-assets.json if it doesn't exist yet
// (because node.js and webpack are being run in parallel in development mode)
export function default_webpack_assets()
{
const webpack_assets =
{
javascript: {},
styles: {},
assets: {}
}
return webpack_assets
}
// adds missing fields, etc
export function normalize_options(options)
{
// parameters check
for (let key of Object.keys(options))
{
switch (key)
{
case 'assets':
if (!is_object(options[key]))
{
throw new Error(`"${key}" configuration parameter must be ` + `an object`)
}
break
case 'debug':
if (typeof options[key] !== 'boolean')
{
throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
}
break
case 'verbose':
if (typeof options[key] !== 'boolean')
{
throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
}
break
case 'webpack_assets_file_path':
case 'webpack_stats_file_path':
if (typeof options[key] !== 'string')
{
throw new Error(`"${key}" configuration parameter must be ` + `a string`)
}
break
case 'alias':
if (!is_object(options[key]))
{
throw new Error(`"${key}" configuration parameter must be ` + `an object`)
}
break
case 'modules_directories':
if (!Array.isArray(options[key]))
{
throw new Error(`"${key}" configuration parameter must be ` + `an array`)
}
break
case 'require_context':
if (typeof options[key] !== 'boolean')
{
throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
}
// Legacy `require_context` option is converted to `patch_require`
console.log('WARNING: `require_context` option is now called `patch_require`')
delete options.require_context
options.patch_require = true
break
case 'patch_require':
if (typeof options[key] !== 'boolean')
{
throw new Error(`"${key}" configuration parameter must be ` + `a boolean`)
}
break
default:
throw new Error(`Unknown configuration parameter "${key}"`)
}
}
// if no assets specified (for whatever reason), make it an empty array
if (!options.assets)
{
// options.assets = {}
throw new Error('You must specify "assets" parameter in webpack-isomorphic-tools configuration')
}
// webpack-assets.json path, relative to the project base path
options.webpack_assets_file_path = options.webpack_assets_file_path || 'webpack-assets.json'
// webpack-stats.json path, relative to the project base path
options.webpack_stats_file_path = options.webpack_stats_file_path || 'webpack-stats.json'
// if Webpack aliases are supplied, validate them
if (options.alias)
{
for (let key of Object.keys(options.alias))
{
if (typeof options.alias[key] !== 'string')
{
throw new Error(`Invalid alias for "${key}": "${options.alias[key]}"`)
}
}
}
// generate names (if required) for each user defined asset type, normalize extensions
for (let asset_type of Object.keys(options.assets))
{
const description = options.assets[asset_type]
// normalize extensions
if (description.extension)
{
// sanity check
if (Array.isArray(description.extension))
{
throw new Error(`Use "extensions" key instead of "extension" for specifying an array of file extensions for assets of type "${asset_type}"`)
}
// sanity check
if (typeof description.extension !== 'string')
{
throw new Error(`"extension" value must be a string for assets of type "${asset_type}"`)
}
// normalize
description.extensions = [description.extension]
delete description.extension
}
// sanity check
if (!description.extensions)
{
throw new Error(`You must specify file extensions for assets of type "${asset_type}"`)
}
// parameters check
for (let key of Object.keys(description))
{
switch (key)
{
case 'extensions':
break
case 'exclude':
case 'include':
if (!Array.isArray(description[key]))
{
throw new Error(`"${key}" must be an array for asset type "${asset_type}"`)
}
for (let clusion of description[key])
{
if (typeof clusion !== 'string'
&& !(clusion instanceof RegExp)
&& typeof clusion !== 'function')
{
throw new Error(`Unsupported object type for exclusion/inclusion "${clusion}" for asset type "${asset_type}"`)
}
}
break
case 'filter':
case 'parser':
case 'path':
if (typeof description[key] !== 'function')
{
throw new Error(`"${key}" must be a function for asset type "${asset_type}"`)
}
break
case 'regular_expression':
if (!(description[key] instanceof RegExp))
{
throw new Error(`"${key}" must be a regular expression for asset type "${asset_type}"`)
}
break
default:
throw new Error(`Unknown property "${key}" for asset type "${asset_type}"`)
}
}
}
}
// alias the path if an alias is found,
// and resolve it to a global filesystem path
export function alias_hook(path, module, project_path, aliases, log)
{
// possibly alias the path
const aliased_path = alias(path, aliases)
// return if an alias not found
if (!aliased_path)
{
return
}
// if an alias is found, require() the correct path
log.debug(`require("${path}") was called and an alias was found, so aliasing to module path "${aliased_path}"`)
// resolve the path to a real filesystem path (resolves `npm link`, etc)
const global_path = require_hacker.resolve(aliased_path, module)
log.debug(` resolved the path for the aliased module to ${global_path}`)
return global_path
// const result = require(global_path)
// // log.debug(` the path was found`)
// return require_hacker.to_javascript_module_source(result)
}
// alias the path provided the aliases map
function alias(path, aliases)
{
// if it's a path to a file - don't interfere
if (starts_with(path, '.') || starts_with(path, '/'))
{
return
}
// extract module name from the path
const slash_index = path.indexOf('/')
const module_name = slash_index >= 0 ? path.substring(0, slash_index) : path
const rest = slash_index >= 0 ? path.substring(slash_index) : ''
// find an alias
const alias = aliases[module_name]
// if an alias is found, require() the correct path
if (alias)
{
return alias + rest
}
}
// converts global asset path to local-to-the-project asset path
export function normalize_asset_path(global_asset_path, project_path)
{
// // if this path is outside project folder,
// // return it as a global path
// if (!starts_with(global_asset_path, project_path + path.sep))
// {
// return global_asset_path
// }
// this path is inside project folder,
// convert it to a relative path
// asset path relative to the project folder
let asset_path = path.relative(project_path, global_asset_path)
// for Windows:
//
// convert Node.js path to a correct Webpack path
asset_path = uniform_path(asset_path)
return asset_path
}
// for Windows:
//
// converts Node.js path to a correct Webpack path
export function uniform_path(asset_path)
{
// correct slashes
asset_path = asset_path.replace(/\\/g, '/')
// add './' in the beginning if it's missing (for example, in case of Windows)
if (asset_path.indexOf('.') !== 0)
{
asset_path = './' + asset_path
}
return asset_path
}