UNPKG

@sketch-hq/sketch-assistant-utils

Version:

Utility functions and types for Sketch Assistants.

305 lines (304 loc) 12.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.process = exports.traverse = exports.addObjectToCache = exports.createEmptyObjectCache = void 0; const sketch_assistant_types_1 = require("@sketch-hq/sketch-assistant-types"); const FOREIGN_OBJECT_CONTEXTS = [ 'foreignLayerStyles', 'foreignSymbols', 'foreignTextStyles', 'foreignSwatches', ]; /** * Create an empty ObjectCache object. */ const createEmptyObjectCache = () => (Object.assign(Object.assign({}, Object.values(sketch_assistant_types_1.FileFormat.ClassValue).reduce((acc, curr) => { return Object.assign({ [curr]: [] }, acc); }, {})), { anyGroup: [], anyLayer: [], document: [] })); exports.createEmptyObjectCache = createEmptyObjectCache; /** * Add a file format object to an ObjectCache instance. */ const addObjectToCache = (object, cache) => { // Use heuristics to determine whether an object is "groupy" or "layery" // and add to the appropriate cache key if so if ('layers' in object) cache.anyGroup.push(object); if ('frame' in object) cache.anyLayer.push(object); // For each class value available in the file format add the object to cache. // This approach is long-winded but gives near 100% type safety switch (object._class) { case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableColorAsset: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableFlowConnection: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableForeignLayerStyle: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableForeignSwatch: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableForeignSymbol: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableForeignTextStyle: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableFreeformGroupLayout: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableGradientAsset: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableHotspotLayer: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableInferredGroupLayout: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSImmutableOverrideProperty: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSJSONFileReference: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.MSJSONOriginalDataReference: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Artboard: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.AssetCollection: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.AttributedString: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Bitmap: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Blur: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Border: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.BorderOptions: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Color: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ColorControls: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.CurvePoint: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ExportFormat: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ExportOptions: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Fill: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.FontDescriptor: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.FontReference: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Gradient: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.GradientStop: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.GraphicsContextSettings: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Group: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ImageCollection: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.InnerShadow: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.LayoutGrid: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Oval: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.OverrideValue: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Page: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ParagraphStyle: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Polygon: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Rect: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Rectangle: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.RulerData: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Shadow: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ShapeGroup: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.ShapePath: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SharedStyle: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SharedStyleContainer: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SharedTextStyleContainer: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SimpleGrid: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Slice: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Star: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.StringAttribute: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Style: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Swatch: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SwatchContainer: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SymbolContainer: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SymbolInstance: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.SymbolMaster: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Text: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.TextStyle: cache[object._class].push(object); break; case sketch_assistant_types_1.FileFormat.ClassValue.Triangle: cache[object._class].push(object); break; case 'document': cache[object._class].push(object); break; } }; exports.addObjectToCache = addObjectToCache; /** * Recursively traverse a Sketch file, while populating various caches and maps. */ const traverse = ({ target, cancelToken, pointers, objects, foreignObjects, objectIds, pointer = '', foreignContext = false, }) => { // Bail early if we've been passed a falsey value or the operation is cancelled if (!target || cancelToken.cancelled) return; // Bail early if input is not an object if (typeof target !== 'object') return; // If target is an array then traverse into each of its elements if (Array.isArray(target)) { for (let index = 0; index < target.length; index++) { exports.traverse({ target: target[index], cancelToken, pointers, objects, foreignObjects, objectIds, pointer: `${pointer}/${index}`, foreignContext, }); } return; } // If this is a Sketch file object with a `_class` then add it to the pointer map if ('_class' in target) { pointers.set(target, pointer); exports.addObjectToCache(target, foreignContext ? foreignObjects : objects); } // If this is an object with an id then add the id to the id set if ('do_objectID' in target) { objectIds.add(target.do_objectID); } // Loop over its properties for (const key in target) { exports.traverse({ target: target[key], cancelToken, pointers, objects, foreignObjects, objectIds, pointer: `${pointer}/${key}`, foreignContext: foreignContext || FOREIGN_OBJECT_CONTEXTS.includes(key), }); } }; exports.traverse = traverse; /** * Generate a ProcessedSketchFile object from a SketchFile object. */ const process = (file, cancelToken) => new Promise((resolve, reject) => { try { const objects = exports.createEmptyObjectCache(); const foreignObjects = exports.createEmptyObjectCache(); const pointers = new Map(); const start = Date.now(); const objectIds = new Set(); exports.traverse({ target: file.contents, cancelToken, pointers, objects, foreignObjects, objectIds, }); resolve({ original: file, objects, foreignObjects, pointers, objectIds, profile: { numObjects: pointers.size, time: Date.now() - start }, }); } catch (error) { reject(error); } }); exports.process = process;