I've played around with the new format a bit and it's really awesome! It really opens up sketch in an entirely new way. Here is a small node script that reads a sketch file, changes a layer name on the page, and saves back to that file:
const fs = require('fs');
// lib to read and write to the zip
const JSZip = require('jszip');
fs.readFile('Untitled3.sketch', function(err, data) {
if(err) throw err;
JSZip.loadAsync(data).then(function(zip) {
// zip contains a json file that describes all the directory & files in the zip file
// read the top level page
// hardcoding page because im lazy ;)
const pagePath = Object.keys(zip.files)[1];
zip.file(pagePath)
.async('string')
.then(function(str) {
const json = JSON.parse(str);
// grab the first layer which in my case is a text layer
const text = json.layers[0];
text.name = 'Changing the layer name';
// write the page json back to the file in the zip
zip.file(pagePath, JSON.stringify(json))
// override the original file
zip
.generateNodeStream({ type:'nodebuffer', streamFiles:true })
.pipe(fs.createWriteStream('Untitled3.sketch'))
.on('finish', () => {
console.log('yay saved file. Open me in sketch to see the changes');
});
});
});
});
The Untitled sketch file is a blank document that and I created one text layer and saved it.
Couple Observations:
- If you change the file while sketch is open, and the user saves the file, you'll get a alert that says something to the effect of: The document could not be saved. The file has been changed by another application
- Some text information (stringValue, paragraph style, font) is encoded and cannot be read.
To get around (1) I did this (not sure if its correct, but after a bit of trial and error works for me):
var document = context.document;
var fileURL = document.fileURL();
// not sure about the 2nd arg
document.readDocumentFromURL_ofType_error(fileURL, "sketch", null);
document.revertToContentsOfURL_ofType_error(fileURL, "sketch", null);
For (2) If you have sketch open you can look at the respective class and there should be some helper method. For example To get the string value of a textLayer, you can look at MSAttributedString.decodeAttributedString
. If you don't have sketch open or want to do some processing outside of sketch you can use coscript REPL:
var archive = NSString.stringWithString(ARCHIVED_STRING);
var data = NSData.alloc().initWithBase64EncodedString_options(archive, 0);
var res = NSKeyedUnarchiver.unarchiveObjectWithData(data);
// string value
log(res.string());
Hopefully this helps anyone just getting started. Can't wait to hack on this some more ?