"use strict"; import tasks from "./tasks"; import { Messages, MessagesRoot, ProcessTaskContext, ReportResult, Settings, TaskInfo, TaskInfoExternal, TaskProcessor, TaskProcessorCallback, TaskProcessorCore } from "./types"; interface IFlags { [flagName: string]: boolean; } const isExternalTask = (task: TaskInfo): task is TaskInfoExternal => (task as TaskInfoExternal).type !== undefined; let tasksCount = 0; // TaskProcessor does not look like EventEmitter, so no need to extend EventEmitter and use `emit' here. const createTaskProcessor = (task: TaskInfo, outerProcessor: TaskProcessorCore, callback: TaskProcessorCallback) => { const taskId = tasksCount++; const errors: string[] = []; const name = task.name || (isExternalTask(task) ? task.type : null); const nameWithId = String(name || "") + "#" + taskId; const getOuterPrefix = (prefix?: string) => { if (!prefix) { return nameWithId; } return `${nameWithId}/${prefix}`; }; const onError = (message: string, prefix?: string) => { errors.push(message); outerProcessor.onError(message, getOuterPrefix(prefix)); }; const onWarn = (message: string, prefix?: string) => outerProcessor.onWarn(message, getOuterPrefix(prefix)); const onInfo = (message: string, prefix?: string) => outerProcessor.onInfo(message, getOuterPrefix(prefix)); const taskWithParameters = isExternalTask(task) ? tasks[task.type](task.params || {}) : task.task; let result: TaskProcessor; result = { context: outerProcessor.context, done: () => { onInfo(`Completed task ${nameWithId}`); callback(errors.join("\r\n")); }, onError, onWarn, onInfo, process: () => { onInfo(`Starting task ${nameWithId}`); taskWithParameters(result)(); }, processTask: (innerTask, innerCallback) => createTaskProcessor(innerTask, result, innerCallback).process(), settings: outerProcessor.settings, }; return result; }; const pushMessage = (list: Messages, message: string, parts: string[], index: number): void => { if (index < parts.length) { if (!list[parts[index]]) { list[parts[index]] = {}; } return pushMessage(list[parts[index]] as Messages, message, parts, index + 1); } if (!list.$messages) { list.$messages = []; } list.$messages.push(message); return; }; const pushMessageRoot = (list: MessagesRoot, message: string, parts: string[]): void => { list.$allMessages.push({ message, prefix: parts.join("/"), }); pushMessage((list as any) as Messages, message, parts, 0); }; const addFlag = (flags: IFlags) => (flagName: string) => { flags[flagName] = true; }; const containsFlag = (flags: IFlags) => (flagName: string) => flags[flagName]; export const processTask = (settings: Settings, task: TaskInfo, context: ProcessTaskContext, callback: (err: any, result: ReportResult) => void) => { const errors: MessagesRoot = { $allMessages: [] }; const warns: MessagesRoot = { $allMessages: [] }; const infos: MessagesRoot = { $allMessages: [] }; const messages: MessagesRoot = { $allMessages: [] }; const messageProcessor = (list: MessagesRoot) => (message: string, prefix: string) => { const parts = prefix.split("/"); pushMessageRoot(list, message, parts); pushMessageRoot(messages, message, parts); }; const flags: IFlags = {}; const processor = createTaskProcessor(task, { context: { ...context, addFlag: addFlag(flags), containsFlag: containsFlag(flags), }, onError: messageProcessor(errors), onInfo: messageProcessor(infos), onWarn: messageProcessor(warns), settings, }, (err) => callback(err, { errors, infos, messages, warns, })); processor.process(); };