UNPKG

node-sketch

Version:

Javascript library to manipulate sketch files

208 lines (179 loc) 6.42 kB
const fs = require('fs'); const path = require('path'); const lib = require('../'); /** * This class represents the sketch file and all this content. * * @property {JSZip} repo - The instance of JSZip containing the raw data * @property {Node} document - The document data * @property {Node} meta - The meta data * @property {Node} user - The user data * @property {Page[]} pages - Array with all pages of the document * @property {Page|undefined} symbolsPage - The "Symbols" page if exists * @property {Node[]} symbols - Array with all local symbols (symbols stored in any page of the document) * @property {Node[]} foreignSymbols - Array with all foreign symbols used in the document (symbols loaded from libraries) * @property {SharedStyle[]} layerStyles - Array with all shared styles of the document * @property {SharedStyle[]} foreignLayerStyles - Array with all shared styles used and loaded from external libraries * @property {SharedStyle[]} textStyles - Array with all text styles of the document * @property {SharedStyle[]} foreignTextStyles - Array with all text styles used and loaded from external libraries * @property {Node[]} colors - Array with the document color palette * @property {Node[]} colorAssets - Array with the document color palette with names * @property {Node[]} gradients - Array with the document gradients palette * @property {Node[]} gradientAssets - Array with the document gradients palette with names */ class Sketch { constructor(repo, document, meta, user, pages) { this._class = 'sketch'; this.repo = repo; this.document = lib.create(this, document); this.meta = lib.create(this, meta); this.user = lib.create(this, user); this.pages = pages.map(page => lib.create(this, page)); } get symbolsPage() { return this.pages.find(page => page.name === 'Symbols'); } get symbols() { return this.pages .map(page => page.getAll('symbolMaster')) .reduce((symbols, currentPage) => symbols.concat(currentPage)); } get foreignSymbols() { return this.document.foreignSymbols.map(symbol => symbol.symbolMaster); } get layerStyles() { return this.document.layerStyles.objects; } get foreignLayerStyles() { return this.document.foreignLayerStyles.map(style => style.localSharedStyle); } get textStyles() { return this.document.layerTextStyles.objects; } get foreignTextStyles() { return this.document.foreignTextStyles.map(style => style.localSharedStyle); } get colors() { return this.document.assets.colors; } get colorAssets() { return this.document.assets.colorAssets; } get gradients() { return this.document.assets.gradients; } get gradientAssets() { return this.document.assets.gradientAssets; } /** * Exports the file previews to other location * * @param {string} dir - The directory path of the exported file. * * @example * //Export all document previews to a directory * sketch.exportPreviews('/path/to/export'); */ exportPreviews(dir) { const previews = this.repo.folder('previews'); return exportFolder(previews, dir); } /** * Exports the file previews to other location * * @param {string} dir - The directory path of the exported file. * * @example * //Export all text previews to a directory * sketch.exportTextPreviews('/path/to/export'); */ exportTextPreviews(dir) { const previews = this.repo.folder('text-previews'); return exportFolder(previews, dir); } /** * Save the document as a sketch file * @example * ns.read('input.sketch').then((sketch) => { * * //modify the sketch data * * sketch.save('output.sketch') * }) * @param {string} file - The file path * @return {Promise} */ save(file) { this._saveJson(); return new Promise((resolve, reject) => { this.repo .generateNodeStream({ type: 'nodebuffer', streamFiles: true, compression: 'DEFLATE' }) .pipe(fs.createWriteStream(file)) .on('finish', () => { resolve(file); }) .on('error', err => { reject(err); }); }); } /** * Save the document into a directory with pretty json * Useful to inspect the json scheme of a sketch file * * @param {string} dir [description] * @return {Promise} */ saveDir(dir) { this._saveJson(true); return exportFolder(this.repo, dir); } /** * @private */ _saveJson(pretty) { const space = pretty ? 2 : 0; this.document.pages = this.pages.map(page => { this.repo.file(`pages/${page.do_objectID}.json`, JSON.stringify(page, null, space)); return { _class: 'MSJSONFileReference', _ref_class: 'MSImmutablePage', _ref: `pages/${page.do_objectID}` }; }); this.repo.file('document.json', JSON.stringify(this.document, null, space)); this.repo.file('meta.json', JSON.stringify(this.meta, null, space)); this.repo.file('user.json', JSON.stringify(this.user, null, space)); } } module.exports = Sketch; function exportFolder(repo, dir) { const promises = []; repo.forEach((name, file) => { promises.push( new Promise((fulfill, reject) => { if (file.dir) { return fulfill(); } const dest = path.join(dir, name); const destDir = path.dirname(dest); if (!fs.existsSync(destDir)) { fs.mkdirSync(destDir); } file.nodeStream() .pipe(fs.createWriteStream(dest)) .on('finish', () => { fulfill(dest); }) .on('error', err => { reject(err); }); }) ); }); return Promise.all(promises); }