Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanslewis committed May 12, 2018
2 parents 9f66fa0 + 046b5d9 commit f175047
Show file tree
Hide file tree
Showing 23 changed files with 759 additions and 595 deletions.
119 changes: 51 additions & 68 deletions Sources/StyleSyncCore/Sketch/SketchDocument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,34 +78,26 @@ public extension SketchDocument {
public let kerning: CGFloat?

public struct Font: Codable {
let sixtyFourBitRepresentation: String
public var fontName: String? {
return fontDescriptor?.fontAttributes[NSFontDescriptor.AttributeName.name] as? String
public let attributes: Attributes
public var fontName: String {
return attributes.fontName
}
public var pointSize: CGFloat? {
return fontDescriptor?.pointSize
}
private var fontDescriptor: NSFontDescriptor? {
return sixtyFourBitRepresentation.unarchivedObject()
}

enum CodingKeys: String, CodingKey {
case sixtyFourBitRepresentation = "_archive"
}
}

public struct PreVersion48Color: Codable {
let sixtyFourBitRepresentation: String
public var color: NSColor? {
return sixtyFourBitRepresentation.unarchivedObject()
public var pointSize: CGFloat {
return attributes.pointSize
}

enum CodingKeys: String, CodingKey {
case sixtyFourBitRepresentation = "_archive"
public struct Attributes: Codable {
public let fontName: String
public let pointSize: CGFloat

enum CodingKeys: String, CodingKey {
case fontName = "name"
case pointSize = "size"
}
}
}

public struct PostVersion48Color: Codable {
public struct Color: Codable {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
Expand All @@ -123,47 +115,31 @@ public extension SketchDocument {
}

public struct ParagraphStyle: Codable {
let sixtyFourBitRepresentation: String
public var paragraphStyle: NSParagraphStyle? {
return sixtyFourBitRepresentation.unarchivedObject()
}
public var textAlignment: NSTextAlignment
public var minimumLineHeight: CGFloat?
public var maximumLineHeight: CGFloat?

enum CodingKeys: String, CodingKey {
case sixtyFourBitRepresentation = "_archive"
}
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
do {
// First try to decode using the old
// standard.
let rawRepresentation = try values.decode(PreVersion48Color.self, forKey: .preVersion48Color)
guard let color = rawRepresentation.color else {
throw Error.failedToParseColor
}
self.color = color
} catch {
let explicitRepresentation = try values.decode(PostVersion48Color.self, forKey: .postVersion48Color)
self.color = explicitRepresentation.color
public init(
textAlignment: NSTextAlignment,
minimumLineHeight: CGFloat?,
maximumLineHeight: CGFloat?
) {
self.textAlignment = textAlignment
self.minimumLineHeight = minimumLineHeight
self.maximumLineHeight = maximumLineHeight
}

self.font = try values.decode(Font.self, forKey: .font)

do {
self.paragraphStyle = try values.decode(ParagraphStyle.self, forKey: .preVersion49ParagraphStyle)
} catch {
self.paragraphStyle = try values.decode(ParagraphStyle.self, forKey: .postVersion49ParagraphStyle)
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.textAlignment = try values.decode(NSTextAlignment.self, forKey: .textAlignment)
self.minimumLineHeight = try? values.decode(CGFloat.self, forKey: .minimumLineHeight)
self.maximumLineHeight = try? values.decode(CGFloat.self, forKey: .maximumLineHeight)
}

do {
self.kerning = try values.decode(CGFloat.self, forKey: .preVersion49Kerning)
} catch {
do {
self.kerning = try values.decode(CGFloat.self, forKey: .postVersion49Kerning)
} catch {
self.kerning = nil
}
enum CodingKeys: String, CodingKey {
case textAlignment = "alignment"
case minimumLineHeight = "minimumLineHeight"
case maximumLineHeight = "maximumLineHeight"
}
}

Expand All @@ -174,23 +150,28 @@ public extension SketchDocument {
self.kerning = kerning
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.color = try values.decode(Color.self, forKey: .color).color
self.font = try values.decode(Font.self, forKey: .font)
self.paragraphStyle = try values.decode(ParagraphStyle.self, forKey: .paragraphStyle)
self.kerning = try? values.decode(CGFloat.self, forKey: .kerning)
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
let postVersion48Color = PostVersion48Color(color: color)
try container.encode(postVersion48Color, forKey: .postVersion48Color)
let color = Color(color: self.color)
try container.encode(color, forKey: .color)
try container.encode(font, forKey: .font)
try container.encode(paragraphStyle, forKey: .postVersion49ParagraphStyle)
try container.encode(kerning, forKey: .postVersion49Kerning)
try container.encode(paragraphStyle, forKey: .paragraphStyle)
try container.encode(kerning, forKey: .kerning)
}

enum CodingKeys: String, CodingKey {
case font = "MSAttributedStringFontAttribute"
case preVersion48Color = "NSColor"
case postVersion48Color = "MSAttributedStringColorDictionaryAttribute"
case preVersion49Kerning = "NSKern"
case postVersion49Kerning = "kerning"
case preVersion49ParagraphStyle = "NSParagraphStyle"
case postVersion49ParagraphStyle = "paragraphStyle"
case color = "MSAttributedStringColorAttribute"
case kerning = "kerning"
case paragraphStyle = "paragraphStyle"
}

enum Error: Swift.Error {
Expand All @@ -202,3 +183,5 @@ public extension SketchDocument {
}
}
}

extension NSTextAlignment: Codable {}
40 changes: 36 additions & 4 deletions Sources/StyleSyncCore/Sketch/SketchManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import Foundation
import Files

public class SketchManager {
// MARK: - Constants

private enum Constant {
static let minimumVersion = Version(major: 50, minor: 0)
}

// MARK: - Stored variables

private var sketchFile: File
Expand All @@ -22,14 +28,40 @@ public class SketchManager {

public func getSketchDocument() throws -> SketchDocument {
print("Extracting styles from \(sketchFile.path)")

let zipManager = try ZipManager(zippedFile: sketchFile)

defer {
// Remove all the unzipped files.
do {
try zipManager.cleanup()
} catch {
ErrorManager.log(error: error, context: .sketch)
}
}

let sketchMetadataFile = try zipManager.getSketchMetadata()
let sketchMetadata: SketchMetadata = try sketchMetadataFile.readAsDecodedJSON()

guard sketchMetadata.appVersion >= Constant.minimumVersion else {
throw Error.unsupportedVersion
}

let sketchDocumentFile = try zipManager.getSketchDocument()
let sketchDocument: SketchDocument = try sketchDocumentFile.readAsDecodedJSON()

// Remove all the unzipped files.
try zipManager.cleanup()

return sketchDocument
}
}

extension SketchManager {
public enum Error: Swift.Error, CustomStringConvertible {
case unsupportedVersion

public var description: String {
switch self {
case .unsupportedVersion:
return "stylesync supports a minimum Sketch version of 50. If you have Sketch v50, simply open your document and save to update it. If you don't, you can download a supported version from: \(GitHubLink.lastSupportedVersionBefore50)"
}
}
}
}
48 changes: 48 additions & 0 deletions Sources/StyleSyncCore/Sketch/SketchMetadata.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// SketchMetadata.swift
// StyleSync
//
// Created by Dylan Lewis on 12/05/2018.
//

import Foundation

public struct SketchMetadata: Codable {
public let appVersion: Version

// MARK: - Codable

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let versionString = try values.decode(String.self, forKey: .appVersionString)
guard let version = Version(versionString: versionString) else {
throw Error.failedToCreateVersion(versionString: versionString)
}
self.appVersion = version
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(appVersion.stringRepresentation, forKey: .appVersionString)
}

enum CodingKeys: String, CodingKey {
case appVersionString = "appVersion"
}
}

// MARK: - Error

extension SketchMetadata {
enum Error: Swift.Error, CustomStringConvertible {
case failedToCreateVersion(versionString: String)

var description: String {
switch self {
case .failedToCreateVersion(let versionString):
return "Failed to create Version from \(versionString)"
}
}
}
}

11 changes: 4 additions & 7 deletions Sources/StyleSyncCore/Styles/TextStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,17 @@ struct TextStyle: Style, Codable {

init?(textStyleObject: SketchDocument.TextStyles.Object, colorStyle: ColorStyle, isDeprecated: Bool = false) {
let textAttributes = textStyleObject.value.textStyle.encodedAttributes
guard
let fontName = textAttributes.font.fontName,
let pointSize = textAttributes.font.pointSize,
let lineHeight = textAttributes.paragraphStyle.paragraphStyle?.maximumLineHeight
else {
guard let lineHeight = textAttributes.paragraphStyle.maximumLineHeight else {
ErrorManager.log(warning: "Failed to parse text style with name \(textStyleObject.name)\n\n\(textStyleObject)", isBug: true)
return nil
}
let font = textAttributes.font

self.init(
name: textStyleObject.name,
identifier: textStyleObject.identifier,
fontName: fontName,
pointSize: pointSize,
fontName: font.fontName,
pointSize: font.pointSize,
kerning: textAttributes.kerning ?? 0,
lineHeight: lineHeight,
colorStyle: colorStyle,
Expand Down
1 change: 1 addition & 0 deletions Sources/StyleSyncCore/Utilities/GitHubLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ enum GitHubLink {
static let templatesDirectory = baseURL.appendingPathComponent("tree/master/Sources/StyleSyncCore/Templates")
static let templateReadme = baseURL.appendingPathComponent("tree/master/Sources/StyleSyncCore/Templates/README.md")
static let personalAccessTokens = URL(string: "https://github.com/settings/tokens")!
static let lastSupportedVersionBefore50 = baseURL.appendingPathComponent("releases/tag/v1.0.2")
}
28 changes: 26 additions & 2 deletions Sources/StyleSyncCore/Versions/Version.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ public struct Version {
.flatMap { component in
return numberFormatter.number(from: component)?.intValue
}
guard

if
versionComponents.count == 1,
let major = versionComponents.first
{
self.init(major: major, minor: 0)
} else if
versionComponents.count == 2,
let major = versionComponents.first,
let minor = versionComponents.last
{
self.init(major: major, minor: minor)
}
else {
return nil
}
self.init(major: major, minor: minor)
}

public var stringRepresentation: String {
Expand Down Expand Up @@ -113,9 +121,25 @@ extension Version {
static let firstVersion = Version(versionString: "1.0")!
}

// MARK: - Equatable

extension Version: Equatable {
public static func == (lhs: Version, rhs: Version) -> Bool {
return lhs.major == rhs.major
&& lhs.minor == rhs.minor
}
}

// MARK: - Comparable

extension Version: Comparable {
public static func <(lhs: Version, rhs: Version) -> Bool {
if lhs.major == rhs.major {
return lhs.minor < rhs.minor
} else if lhs.major < rhs.major {
return true
} else {
return false
}
}
}
28 changes: 23 additions & 5 deletions Sources/StyleSyncCore/Zip/ZipManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct ZipManager {

private enum Constant {
static let exportFolderName = "UnzippedSketchFiles"
static let sketchMetadataFileName = "meta.json"
static let sketchDocumentFileName = "document.json"
}

Expand All @@ -33,18 +34,35 @@ struct ZipManager {

// MARK: - Actions

func getSketchMetadata() throws -> File {
let folder = try rawSketchFilesDirectory()
return try folder.file(named: Constant.sketchMetadataFileName)
}

func getSketchDocument() throws -> File {
let exportFolder = try parentFolder.createSubfolder(named: Constant.exportFolderName)
try shellOut(to: .unzip(zippedFile: zippedFile.path, exportDirectory: exportFolder.path))

let sketchDocument = try exportFolder.file(named: Constant.sketchDocumentFileName)
return sketchDocument
let folder = try rawSketchFilesDirectory()
return try folder.file(named: Constant.sketchDocumentFileName)
}

func cleanup() throws {
let exportFolder = try parentFolder.subfolder(named: Constant.exportFolderName)
try shellOut(to: .removeDirectory(directory: exportFolder.path))
}

// MARK: - Helpers

private func rawSketchFilesDirectory() throws -> Folder {
let exportFolder: Folder
do {
exportFolder = try parentFolder.subfolder(named: Constant.exportFolderName)
} catch {
exportFolder = try parentFolder.createSubfolder(named: Constant.exportFolderName)
}
if exportFolder.files.count == 0 {
try shellOut(to: .unzip(zippedFile: zippedFile.path, exportDirectory: exportFolder.path))
}
return exportFolder
}
}

extension ZipManager {
Expand Down
Loading

0 comments on commit f175047

Please sign in to comment.