okam-build
Version:
The build tool for Okam develop framework
324 lines (277 loc) • 8.47 kB
JavaScript
/**
* @file The processor helper
* @author sparklewhy@gmail.com
*/
;
/* eslint-disable fecs-min-vars-per-destructure */
/* eslint-disable fecs-prefer-destructure */
/* eslint-disable fecs-use-for-of */
const mm = require('minimatch');
const customRequire = require('../../util').require;
const {merge} = require('../../util');
const BUILTIN_PROCESSORS = require('../type').BUILTIN_PROCESSORS;
const initBabelProcessorOptions = require('./init-babel');
const initViewProcessorOptions = require('./init-view');
/**
* The default babel processor to use
*
* @const
* @type {string}
*/
const DEFAULT_BABEL_PROCESSOR = 'babel';
function hasBabelProcessor(processorName) {
return (processorName === 'babel'
|| processorName === 'babel7'
|| processorName === 'typescript'
);
}
function getDefaultBabelProcessor(processorsConfig) {
if (!processorsConfig) {
return DEFAULT_BABEL_PROCESSOR;
}
let processorNames = processorsConfig;
if (Array.isArray(processorsConfig)) {
processorNames = processorsConfig.map(item => item.name);
}
else {
processorNames = Object.keys(processorsConfig);
}
let defaultProcessor;
processorNames.some(name => {
let hasBabel = hasBabelProcessor(name);
if (hasBabel) {
defaultProcessor = name;
return true;
}
return false;
});
defaultProcessor || (defaultProcessor = DEFAULT_BABEL_PROCESSOR);
if (defaultProcessor === 'typescript') {
defaultProcessor = 'babel7';
}
return defaultProcessor;
}
function isMatch(file, pattern) {
let typeStr = typeof pattern;
if (typeStr === 'string') {
return mm(file.path, pattern, {matchBase: true});
}
else if (typeStr === 'function') {
return !!pattern(file);
}
else if (pattern instanceof RegExp) {
return pattern.test(file.path);
}
return false;
}
function normalizeProcessor(processor, file) {
if (!processor) {
return;
}
if (typeof processor === 'function') {
processor = processor(file);
}
let processorName = processor;
let processorOpts;
if (Array.isArray(processorName)) {
let arr = processorName;
if (arr.length === 2
&& typeof arr[0] === 'string'
&& typeof arr[1] === 'object'
) {
processorName = arr[0];
processorOpts = arr[1];
}
else {
return arr.map(item => ({
name: item,
options: {}
}));
}
}
else if (typeof processor === 'object') {
processorName = processor.name;
processorOpts = processor.options;
}
return {
name: processorName,
options: processorOpts || {}
};
}
function resolveProcessor(name, root, logger) {
let resolveNames = [name];
let optName = `okam-plugin-${name}`;
if (!resolveNames.includes(optName)) {
resolveNames.unshift(optName);
}
let result;
resolveNames.some(k => {
try {
result = customRequire(k, root);
}
catch (ex) {
// ignore
}
return !!result;
});
if (!result) {
logger.error(
`unknown processor name ${name},`,
'you can try execute: `npm i',
resolveNames[0] + ' -D`',
'or install `' + resolveNames[1] + '`',
'to fix it'
);
}
return result;
}
function getBuiltinProcessor(file, processorInfo, buildManager) {
let {name: processorName, options: processorOpts} = processorInfo;
let {root, logger} = buildManager;
let result = BUILTIN_PROCESSORS[processorName];
if (!result) {
result = resolveProcessor(processorName, root, logger);
if (result) {
result = {
processor: result
};
// cache custom processor
BUILTIN_PROCESSORS[processorName] = result;
}
else {
return;
}
}
let referProcessorName = result.refer;
if (!result._resolved && result.deps && result.deps.length) {
result._resolved = true;
try {
customRequire.ensure(processorName, result.deps, root);
}
catch (ex) {
logger.error(ex.toString());
process.exit(1);
}
}
// merge default options
let defaultOpts = result.options;
if (defaultOpts) {
processorOpts = merge({}, defaultOpts, processorOpts);
}
let isNativeViewProcessor = processorName === 'nativeView';
// init babel transform extra options
let isUsingBabelProcessor = hasBabelProcessor(referProcessorName || processorName);
if (isUsingBabelProcessor) {
processorOpts = initBabelProcessorOptions(
file, processorOpts, buildManager
);
}
else if (processorName === 'view' || isNativeViewProcessor) {
processorOpts = initViewProcessorOptions(
file, processorOpts, buildManager, isNativeViewProcessor
);
}
let handler = result.processor;
if (typeof handler === 'string') {
handler = customRequire(handler);
}
// call before hook
let hook = result.hook;
if (hook && typeof hook.before === 'function') {
hook.before(file, processorOpts);
}
return {
name: processorName,
handler,
options: processorOpts,
rext: result.rext
};
}
function getProcessor(processor, file, buildManager) {
let processorInfo = normalizeProcessor(processor, file);
if (!processorInfo) {
return;
}
if (!Array.isArray(processorInfo)) {
processorInfo = [processorInfo];
}
return processorInfo.map(item => {
if (typeof item.name === 'string') {
return getBuiltinProcessor(file, item, buildManager);
}
return item;
});
}
function addScriptDefaultBabelProcessor(file, buildManager, processors) {
let hasBabel = processors.some(item => hasBabelProcessor(item.name));
if (!hasBabel) {
processors.unshift(
getBuiltinProcessor(
file, {name: DEFAULT_BABEL_PROCESSOR, options: {}}, buildManager
)
);
}
}
function findMatchProcessor(file, rules, buildManager) {
let logger = buildManager.logger;
let matchProcessors = [];
let unknownProcessors = [];
rules || (rules = []);
for (let r = 0, rLen = rules.length; r < rLen; r++) {
let ruleItem = rules[r];
if (!isMatch(file, ruleItem.match)) {
continue;
}
let processors = ruleItem.processors || [];
let isArr = Array.isArray(processors);
let isFunc = typeof processors === 'function';
if (isFunc) {
logger.warn('`processors` function type is not supported');
continue;
}
for (let k in processors) {
if (processors.hasOwnProperty(k)) {
let item = processors[k];
if (!isArr) {
item = {name: k, options: item};
}
let result = getProcessor(item, file, buildManager);
if (Array.isArray(result)) {
matchProcessors.push.apply(matchProcessors, result);
}
else if (result) {
matchProcessors.push(result);
}
else {
unknownProcessors.push({ruleIndex: r, processorIndex: k});
}
}
}
}
if (unknownProcessors.length) {
logger.warn('unknown rule processors', unknownProcessors);
}
// add default babel processor for script file if none babel processor existed
if (file.isScript) {
addScriptDefaultBabelProcessor(file, buildManager, matchProcessors);
}
return matchProcessors;
}
exports.getBuiltinProcessor = function (name, options) {
let result = BUILTIN_PROCESSORS[name];
if (!result) {
return;
}
let handler = result.processor;
if (typeof handler === 'string') {
handler = customRequire(handler);
}
return {
name,
handler,
options,
rext: result.rext
};
};
exports.findMatchProcessor = findMatchProcessor;
exports.getDefaultBabelProcessor = getDefaultBabelProcessor;