From fcb880ca811cea3994cd6510f7beb01b283d3050 Mon Sep 17 00:00:00 2001 From: Andrey Chalkin Date: Tue, 28 Jul 2020 02:15:06 +0700 Subject: [PATCH] feat: added Slice shape (#127) --- models/Bitmap/Bitmap.js | 5 +- models/Color/Color.js | 4 +- models/Document/Document.js | 6 +-- models/Layer/Layer.js | 4 +- models/Layer/Layer.test.js | 6 +-- models/Page/Page.js | 4 +- models/Sketch/Sketch.js | 2 +- models/Sketch/Sketch.test.js | 20 ++++---- models/Slice/Slice.js | 73 +++++++++++++++++++++++++++++ models/Slice/index.d.ts | 37 +++++++++++++++ models/Slice/index.js | 14 ++++++ models/Style/Style.js | 16 +++---- models/SymbolMaster/SymbolMaster.js | 14 +++--- models/index.d.ts | 2 + models/index.js | 1 + 15 files changed, 166 insertions(+), 42 deletions(-) create mode 100644 models/Slice/Slice.js create mode 100644 models/Slice/index.d.ts create mode 100644 models/Slice/index.js diff --git a/models/Bitmap/Bitmap.js b/models/Bitmap/Bitmap.js index 229ece4..eda8996 100644 --- a/models/Bitmap/Bitmap.js +++ b/models/Bitmap/Bitmap.js @@ -75,10 +75,7 @@ class Bitmap extends Layer { style: new Style(args.style), layers: args.layers || [], }); - const fileHash = crypto - .createHash('sha1') - .update(args.filePath) - .digest('hex'); + const fileHash = crypto.createHash('sha1').update(args.filePath).digest('hex'); this.image._ref = `images/${fileHash}.png`; fs.ensureDirSync(STORAGE_IMG_DIR); fs.copyFileSync(args.filePath, `${STORAGE_DIR}/${this.image._ref}`); diff --git a/models/Color/Color.js b/models/Color/Color.js index b370f30..488b1ba 100644 --- a/models/Color/Color.js +++ b/models/Color/Color.js @@ -57,8 +57,8 @@ class Color { } // Map all tinycolor's methods // TODO: should check if this will cause performance issues - Object.keys(TinyColor.prototype).forEach(key => { - this[key] = arg => { + Object.keys(TinyColor.prototype).forEach((key) => { + this[key] = (arg) => { const ret = this._getTinyColor()[key](arg); // If the return value is a TinyColor class, // it is modifying the value diff --git a/models/Document/Document.js b/models/Document/Document.js index 67b298b..a8e4a67 100644 --- a/models/Document/Document.js +++ b/models/Document/Document.js @@ -63,9 +63,9 @@ class Document { Object.assign(this, json); // Create nested classes this.layerTextStyles.objects = this.layerTextStyles.objects.map( - sharedStyle => new SharedStyle(null, sharedStyle) + (sharedStyle) => new SharedStyle(null, sharedStyle) ); - this.layerStyles.objects = this.layerStyles.objects.map(sharedStyle => new SharedStyle(null, sharedStyle)); + this.layerStyles.objects = this.layerStyles.objects.map((sharedStyle) => new SharedStyle(null, sharedStyle)); } else { const id = args.id || uuid().toUpperCase(); @@ -89,7 +89,7 @@ class Document { * @returns {SharedStyle} */ getLayerStyle(name) { - return this.layerStyles.objects.find(style => style.name === name); + return this.layerStyles.objects.find((style) => style.name === name); } /** diff --git a/models/Layer/Layer.js b/models/Layer/Layer.js index 8a89bc1..beff980 100644 --- a/models/Layer/Layer.js +++ b/models/Layer/Layer.js @@ -85,7 +85,7 @@ class Layer { // getGroup(id) {} getGroups() { - return this.layers.filter(layer => layer._class === 'group'); + return this.layers.filter((layer) => layer._class === 'group'); } /** @@ -112,7 +112,7 @@ class Layer { } const childLayers = current.getLayers(); if (childLayers !== undefined) { - childLayers.forEach(layer => { + childLayers.forEach((layer) => { list.push(layer); getRecursiveLayers(layer, list); }); diff --git a/models/Layer/Layer.test.js b/models/Layer/Layer.test.js index c684c37..7924196 100644 --- a/models/Layer/Layer.test.js +++ b/models/Layer/Layer.test.js @@ -35,7 +35,7 @@ describe('getLayers', () => { group.addLayer(text1); group.addLayer(text2); - const layers = group.getLayers().map(l => l.name); + const layers = group.getLayers().map((l) => l.name); expect(layers.sort()).toEqual(['text1', 'text2'].sort()); }); @@ -55,7 +55,7 @@ describe('getLayers', () => { innerGroup.addLayer(text); outerGroup.addLayer(innerGroup); - const layers = outerGroup.getLayers().map(l => l.name); + const layers = outerGroup.getLayers().map((l) => l.name); expect(layers.sort()).toEqual(['inner group'].sort()); }); @@ -77,7 +77,7 @@ describe('getAllLayers', () => { innerGroup.addLayer(text); outerGroup.addLayer(innerGroup); - const layers = outerGroup.getAllLayers().map(l => l.name); + const layers = outerGroup.getAllLayers().map((l) => l.name); expect(layers.sort()).toEqual(['inner group', 'text'].sort()); }); diff --git a/models/Page/Page.js b/models/Page/Page.js index b743b07..0f9efd0 100644 --- a/models/Page/Page.js +++ b/models/Page/Page.js @@ -57,7 +57,7 @@ class Page extends Group { * @returns {Artboard[]} */ getArtboards(predicate) { - const arr = this.layers.filter(layer => layer._class === 'artboard'); + const arr = this.layers.filter((layer) => layer._class === 'artboard'); if (predicate) { return arr.filter(predicate); } @@ -70,7 +70,7 @@ class Page extends Group { * @returns {Artboard} */ getArtboard(name) { - return this.getArtboards().find(artboard => artboard.name === name); + return this.getArtboards().find((artboard) => artboard.name === name); } /** diff --git a/models/Sketch/Sketch.js b/models/Sketch/Sketch.js index 99b8545..da99dd2 100644 --- a/models/Sketch/Sketch.js +++ b/models/Sketch/Sketch.js @@ -187,7 +187,7 @@ class Sketch { }) .pipe(fs.createWriteStream(output)) .on('error', reject) - .on('finish', function () { + .on('finish', () => { fs.removeSync(STORAGE_DIR); resolve(output); }) diff --git a/models/Sketch/Sketch.test.js b/models/Sketch/Sketch.test.js index 0b92f97..1253216 100644 --- a/models/Sketch/Sketch.test.js +++ b/models/Sketch/Sketch.test.js @@ -28,13 +28,13 @@ describe('Sketch', () => { }); describe('build', () => { - it('should work', async done => { + it('should work', async (done) => { const sketch = await Sketch.fromFile(`${process.cwd()}/__tests__/__sketch-files/test.sketch`); expect(sketch).toBeDefined(); done(); }); - it('should work when file is Buffer', async done => { + it('should work when file is Buffer', async (done) => { const fileBuffer = fs.readFileSync(`${process.cwd()}/__tests__/__sketch-files/test.sketch`); const sketch = await Sketch.fromFile(fileBuffer); expect(sketch).toBeDefined(); @@ -42,15 +42,15 @@ describe('Sketch', () => { }); it('should have the same do_objectID', () => - Sketch.fromFile(`${process.cwd()}/__tests__/__sketch-files/test.sketch`).then(sketch => { + Sketch.fromFile(`${process.cwd()}/__tests__/__sketch-files/test.sketch`).then((sketch) => { const artboard = sketch.getPage('Page 1').getArtboard('Artboard'); expect(artboard.do_objectID).toBe('5863D14C-8C6E-4C73-801F-A5BF691CF415'); })); it('should build', () => Sketch.fromFile(`${process.cwd()}/__tests__/__sketch-files/test.sketch`) - .then(sketch => sketch.build(`${process.cwd()}/__tests__/__output/test2.sketch`)) - .then(output => { + .then((sketch) => sketch.build(`${process.cwd()}/__tests__/__output/test2.sketch`)) + .then((output) => { expect(output).toEqual(`${process.cwd()}/__tests__/__output/test2.sketch`); })); }); @@ -58,7 +58,7 @@ describe('Sketch', () => { describe('add shared text style', () => { it('should work', () => Sketch.fromFile(`${process.cwd()}/__tests__/__sketch-files/test.sketch`) - .then(sketch => { + .then((sketch) => { const textStyle = SharedStyle.TextStyle({ name: 'foobar', }); @@ -79,7 +79,7 @@ describe('Sketch', () => { sketch.document.addLayerStyle(layerStyle); return sketch.build(`${process.cwd()}/__tests__/__output/test3.sketch`); }) - .then(output => { + .then((output) => { expect(output).toEqual(`${process.cwd()}/__tests__/__output/test3.sketch`); })); }); @@ -87,7 +87,7 @@ describe('Sketch', () => { describe('add page', () => { it('should work', () => Sketch.fromFile(`${process.cwd()}/__tests__/__sketch-files/test.sketch`) - .then(sketch => { + .then((sketch) => { const page = new Page({ name: 'my page', }); @@ -102,14 +102,14 @@ describe('Sketch', () => { sketch.addArtboard(page.getID(), artboard); return sketch.build(`${process.cwd()}/__tests__/__output/test4.sketch`); }) - .then(output => { + .then((output) => { expect(output).toEqual(`${process.cwd()}/__tests__/__output/test4.sketch`); })); }); describe('from extracted file', () => { it('should work', () => { - Sketch.fromExtractedFile(`${process.cwd()}/__tests__/__sketch-files/test-sketch`).then(sketch => { + Sketch.fromExtractedFile(`${process.cwd()}/__tests__/__sketch-files/test-sketch`).then((sketch) => { expect(sketch).toBeDefined(); expect(sketch.getPages().length).toBe(2); }); diff --git a/models/Slice/Slice.js b/models/Slice/Slice.js new file mode 100644 index 0000000..1f5f772 --- /dev/null +++ b/models/Slice/Slice.js @@ -0,0 +1,73 @@ +/* + * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with + * the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +const uuid = require('uuid-v4'); +const Color = require('../Color'); +const Style = require('../Style'); +const Rect = require('../Rect'); +const ExportOptions = require('../ExportOptions'); + +class Slice { + static get Model() { + return { + _class: 'slice', + booleanOperation: -1, + isFixedToViewport: false, + isFlippedHorizontal: false, + isFlippedVertical: false, + isLocked: false, + isVisible: true, + layerListExpandedType: 1, + nameIsFixed: false, + resizingConstraint: 63, + resizingType: 0, + rotation: 0, + shouldBreakMaskChain: false, + hasBackgroundColor: false, + }; + } + + /** + * @param {Object} args + * @param {Object} json + */ + constructor(args, json) { + if (json) { + Object.assign(this, json); + this.exportOptions = new ExportOptions(null, json.exportOptions); + this.frame = new Rect(null, json.frame); + this.style = new Style(null, json.style); + this.backgroundColor = new Color(null, json.backgroundColor); + } + if (args) { + const id = args.id || uuid().toUpperCase(); + + Object.assign(this, { + ...Slice.Model, + ...args, + name: args.name || id, + do_objectID: id, + exportOptions: new ExportOptions(args.exportOptions), + frame: new Rect(args.frame), + style: new Style(args.style), + backgroundColor: new Color(args.color), + }); + } + } + + static fromJSON(json) { + return new Slice(null, json); + } +} + +module.exports = Slice; diff --git a/models/Slice/index.d.ts b/models/Slice/index.d.ts new file mode 100644 index 0000000..6264398 --- /dev/null +++ b/models/Slice/index.d.ts @@ -0,0 +1,37 @@ +import Color from '../Color'; +import ExportOptions from '../ExportOptions'; +import Rect from '../Rect'; +import Style from '../Style'; + +declare class Slice { + _class: 'slice'; + do_objectID: string; + booleanOperation: number; + exportOptions: ExportOptions; + frame: Rect; + isFixedToViewport: boolean; + isFlippedHorizontal: boolean; + isFlippedVertical: boolean; + isLocked: boolean; + isVisible: boolean; + layerListExpandedType: number; + name: string; + nameIsFixed: boolean; + resizingConstraint: number; + resizingType: number; + rotation: number; + shouldBreakMaskChain: boolean; + style: Style; + hasBackgroundColor: boolean; + backgroundColor: Color; + + constructor(args: Partial) + constructor(args: any) + constructor(args: null | undefined, json: Slice) + constructor(args: null | undefined, json: any) + + static fromJSON(json: Slice): Slice + static fromJSON(json: any): Slice +} + +export = Slice; diff --git a/models/Slice/index.js b/models/Slice/index.js new file mode 100644 index 0000000..dfbf95b --- /dev/null +++ b/models/Slice/index.js @@ -0,0 +1,14 @@ +/* + * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with + * the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +module.exports = require('./Slice'); diff --git a/models/Style/Style.js b/models/Style/Style.js index 1d97248..9a17577 100644 --- a/models/Style/Style.js +++ b/models/Style/Style.js @@ -51,8 +51,8 @@ class Style { const id = args.id || uuid().toUpperCase(); return new Style({ id, - fills: (args.fills || []).map(fill => new Fill(fill)), - borders: (args.borders || []).map(border => new Border(border)), + fills: (args.fills || []).map((fill) => new Fill(fill)), + borders: (args.borders || []).map((border) => new Border(border)), }); } @@ -76,16 +76,16 @@ class Style { if (json) { Object.assign(this, json); if (this.textStyle) this.textStyle = new TextStyle(null, this.textStyle); - if (this.fills) this.fills = this.fills.map(fill => new Fill(null, fill)); - if (this.borders) this.borders = this.borders.map(border => new Border(null, border)); - if (this.shadows) this.shadows = this.shadows.map(shadow => new Shadow(null, shadow)); + if (this.fills) this.fills = this.fills.map((fill) => new Fill(null, fill)); + if (this.borders) this.borders = this.borders.map((border) => new Border(null, border)); + if (this.shadows) this.shadows = this.shadows.map((shadow) => new Shadow(null, shadow)); } else { const id = args.id || uuid().toUpperCase(); Object.assign(this, Style.Model, { do_objectID: id, - borders: (args.borders || []).map(border => new Border(border)), - fills: (args.fills || []).map(fill => new Fill(fill)), - shadows: (args.shadows || []).map(shadow => new Shadow(shadow)), + borders: (args.borders || []).map((border) => new Border(border)), + fills: (args.fills || []).map((fill) => new Fill(fill)), + shadows: (args.shadows || []).map((shadow) => new Shadow(shadow)), textStyle: args.textStyle ? new TextStyle(args.textStyle) : undefined, }); } diff --git a/models/SymbolMaster/SymbolMaster.js b/models/SymbolMaster/SymbolMaster.js index ccdda40..6f3d715 100644 --- a/models/SymbolMaster/SymbolMaster.js +++ b/models/SymbolMaster/SymbolMaster.js @@ -96,7 +96,7 @@ class SymbolMaster extends Artboard { } break; case 'group': - prop.layers.forEach(l => { + prop.layers.forEach((l) => { getOverrideNames(l, overrideNames); }); break; @@ -106,7 +106,7 @@ class SymbolMaster extends Artboard { return overrideNames; }; - getOverrideNames(layer, []).forEach(name => { + getOverrideNames(layer, []).forEach((name) => { this.overrideProperties.push({ ...MSImmutableOverrideProperty, canOverride, @@ -127,15 +127,15 @@ class SymbolMaster extends Artboard { * @property {string|Object} [args[].style] - for textStyles only, pass in TextStyle object or do_objectID */ updateInstance(symbolInstance, args) { - args.forEach(arg => { - const overrideLayer = this.getAllLayers().find(l => l.name === arg.name); + args.forEach((arg) => { + const overrideLayer = this.getAllLayers().find((l) => l.name === arg.name); if (overrideLayer !== undefined) { const overrideName = overrideLayer.do_objectID; symbolInstance.overrideValues - .filter(prop => prop.overrideName.split('_')[0] === overrideName) - .forEach(prop => { + .filter((prop) => prop.overrideName.split('_')[0] === overrideName) + .forEach((prop) => { if (prop.overrideName.includes('_stringValue')) { prop.value = arg.value; } @@ -170,7 +170,7 @@ class SymbolMaster extends Artboard { allowsOverrides: this.allowsOverrides, }); - symbolInstance.overrideValues = this.overrideProperties.map(prop => ({ + symbolInstance.overrideValues = this.overrideProperties.map((prop) => ({ _class: 'overrideValue', do_objectID: uuid().toUpperCase(), overrideName: prop.overrideName, diff --git a/models/index.d.ts b/models/index.d.ts index b6ed530..a2b7474 100644 --- a/models/index.d.ts +++ b/models/index.d.ts @@ -25,6 +25,7 @@ import ShapeGroup from './ShapeGroup'; import ShapePath from './ShapePath'; import SharedStyle from './SharedStyle'; import Sketch from './Sketch'; +import Slice from './Slice'; import StringAttribute from './StringAttribute'; import Style from './Style'; import SymbolInstance from './SymbolInstance'; @@ -64,6 +65,7 @@ export { ShapePath, SharedStyle, Sketch, + Slice, StringAttribute, Style, SymbolInstance, diff --git a/models/index.js b/models/index.js index 5f7e498..4f19f23 100644 --- a/models/index.js +++ b/models/index.js @@ -39,6 +39,7 @@ module.exports = { ShapePath: require('./ShapePath'), SharedStyle: require('./SharedStyle'), Sketch: require('./Sketch'), + Slice: require('./Slice'), StringAttribute: require('./StringAttribute'), Style: require('./Style'), SymbolInstance: require('./SymbolInstance'),