UNPKG

@sketch-hq/sketch-assistant-utils

Version:

Utility functions and types for Sketch Assistants.

138 lines (137 loc) 5.54 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.runMultipleAssistants = exports.createRunRejection = exports.isRunRejection = void 0; const assistant_1 = require("../../assistant"); const run_assistant_1 = require("../run-assistant"); const ignore_1 = require("../ignore"); const assistant_config_1 = require("../../assistant-config"); function isRunRejection(val) { if (!val) return false; if (typeof val !== 'object') return false; if (!('code' in val)) return false; return true; } exports.isRunRejection = isRunRejection; /** * Create a RunRejection object. */ const createRunRejection = (message, code = 'runError', error) => { return { message: `Run failed: ${error instanceof Error ? `${message} ${error.message}` : message}`, code, }; }; exports.createRunRejection = createRunRejection; /** * Throw with a "cancelled" rejection if the current operation signals a cancellation from outside. */ const exitIfCancelled = (cancelToken) => { if (cancelToken.cancelled) { throw exports.createRunRejection('Run cancelled by external signal', 'cancelled'); } }; /** * Return the set of active rules for an Assistant. Active rules are 1) activated in the config, * 2) supported by the current platform and 3) not full ignored. */ const getActiveRules = (assistant, env, ignore) => assistant.rules .filter((rule) => assistant_config_1.isRuleActive(assistant.config, rule.name)) // Rule turned on in config .filter((rule) => (rule.runtime ? rule.runtime === env.runtime : true)) // Rule platform is supported .filter((rule) => !ignore_1.isRuleFullIgnored(ignore, assistant.name, rule.name)); /** * Wrapped by the exported function so even uncaught errors are consistently returned * as RunRejections. */ const innerRunMultipleAssistants = (input) => __awaiter(void 0, void 0, void 0, function* () { const { cancelToken, env, processedFile, assistants, getImageMetadata, timeBudgets } = input; let { ignore } = input; if (Object.keys(assistants).length === 0) { throw exports.createRunRejection('No Assistants found to run'); } ignore = ignore_1.pruneAssistants(ignore, assistants); ignore = ignore_1.pruneObjects(ignore, processedFile); const results = {}; const definitions = []; // Prepare assistants, that is, resolve the Assistant package exports into // assistant functions ready for running. for (const [assistantName, assistant] of Object.entries(assistants)) { try { const def = yield assistant_1.prepare(assistant, env); if (def.name !== assistantName) { throw Error(`Assistant name "${def.name}" does not match it's package name "${assistantName}"`); } definitions.push(def); } catch (error) { results[assistantName] = { code: 'error', error: { message: `Assistant preparation failed: ${error.message}`, }, }; } } exitIfCancelled(cancelToken); // Caculate the rule timeout const totalRules = definitions.reduce((acc, assistant) => acc + getActiveRules(assistant, env, ignore).length, 0); const ruleTimeout = Math.min(Math.max(Math.trunc(timeBudgets.totalMs / totalRules), timeBudgets.minRuleTimeoutMs), timeBudgets.maxRuleTimeoutMs); // For each definition prune any ignored rules, no longer present in the // Assistant for (const assistant of definitions) { ignore = ignore_1.pruneRules(ignore, assistant); } // Run assistants against the file. for (const assistant of definitions) { if (cancelToken.cancelled) break; try { results[assistant.name] = { code: 'success', result: yield run_assistant_1.runAssistant(processedFile, assistant, env, cancelToken, getImageMetadata, ignore, ruleTimeout), }; } catch (error) { results[assistant.name] = { code: 'error', error: { message: `Assistant run failed: ${error.message}`, }, }; } } exitIfCancelled(cancelToken); return { assistants: results, ignore, input, }; }); /** * Run multiple assistants. */ const runMultipleAssistants = (input) => __awaiter(void 0, void 0, void 0, function* () { try { return yield innerRunMultipleAssistants(input); } catch (error) { if (isRunRejection(error)) { throw error; } else { throw exports.createRunRejection('Unhandled error', 'runError', error); } } }); exports.runMultipleAssistants = runMultipleAssistants;