From 4561fd0068692ea03b645d63e5dfd566bfb29143 Mon Sep 17 00:00:00 2001 From: John Coates Date: Thu, 17 Mar 2016 00:34:43 -0700 Subject: [PATCH] fix crash on empty Sass file --- .../CSSketch Helper.xcodeproj/project.pbxproj | 6 ++++ .../src/Categories/NSError+CSSketch.h | 15 ++++++++ .../src/Categories/NSError+CSSketch.m | 27 ++++++++++++++ .../src/Controllers/CSKStylesheet.m | 27 ++++++++------ CSSketch Helper/src/Headers/PrefixHeader.pch | 3 ++ External/CocoaSass/CocoaSass/CocoaSass.m | 36 +++++++++++++------ 6 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 CSSketch Helper/src/Categories/NSError+CSSketch.h create mode 100644 CSSketch Helper/src/Categories/NSError+CSSketch.m diff --git a/CSSketch Helper/CSSketch Helper.xcodeproj/project.pbxproj b/CSSketch Helper/CSSketch Helper.xcodeproj/project.pbxproj index 59097a7..d029651 100644 --- a/CSSketch Helper/CSSketch Helper.xcodeproj/project.pbxproj +++ b/CSSketch Helper/CSSketch Helper.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ FA56F7E31BC0E15E005673E0 /* CSSketch Helper.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = FA56F7CF1BC0D6C4005673E0 /* CSSketch Helper.bundle */; }; FA6F46F41C5EB0A0002EE579 /* libCocoaSass.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA6F46F31C5EB095002EE579 /* libCocoaSass.a */; }; FA6F46F71C5EB74F002EE579 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = FA6F46F61C5EB74F002EE579 /* libc++.tbd */; }; + FA795BCD1C9A8FB20050571B /* NSError+CSSketch.m in Sources */ = {isa = PBXBuildFile; fileRef = FA795BCC1C9A8FB20050571B /* NSError+CSSketch.m */; }; FA7D76C21BC1A5BA00FCDEF5 /* CSKLess.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7D76C11BC1A5BA00FCDEF5 /* CSKLess.m */; }; FA7D76D81BC1AB6900FCDEF5 /* CSK_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = FA7D76D71BC1AB6900FCDEF5 /* CSK_Tests.m */; }; FA7D76E41BC1ABFD00FCDEF5 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA7D76E21BC1ABF600FCDEF5 /* JavaScriptCore.framework */; }; @@ -156,6 +157,8 @@ FA6F46EE1C5EB095002EE579 /* CocoaSass.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CocoaSass.xcodeproj; path = ../external/CocoaSass/CocoaSass.xcodeproj; sourceTree = ""; }; FA6F46F51C5EB0B7002EE579 /* CocoaSass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CocoaSass.h; path = ../external/CocoaSass/CocoaSass/CocoaSass.h; sourceTree = ""; }; FA6F46F61C5EB74F002EE579 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; + FA795BCB1C9A8FB20050571B /* NSError+CSSketch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+CSSketch.h"; sourceTree = ""; }; + FA795BCC1C9A8FB20050571B /* NSError+CSSketch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+CSSketch.m"; sourceTree = ""; }; FA7BFD801BCCAD5C000D9AFB /* RS_MSTextLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RS_MSTextLayer.h; sourceTree = ""; }; FA7BFD811BCCAD5C000D9AFB /* RS_MSTextLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RS_MSTextLayer.m; sourceTree = ""; }; FA7D76C01BC1A5BA00FCDEF5 /* CSKLess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSKLess.h; sourceTree = ""; }; @@ -224,6 +227,8 @@ children = ( FA0E95D91BCB279C00CDD8EF /* NSString+Paths.h */, FA0E95DA1BCB279C00CDD8EF /* NSString+Paths.m */, + FA795BCB1C9A8FB20050571B /* NSError+CSSketch.h */, + FA795BCC1C9A8FB20050571B /* NSError+CSSketch.m */, ); path = Categories; sourceTree = ""; @@ -720,6 +725,7 @@ FACF8FBA1BCC28320062D8F8 /* CSKDocumentController.m in Sources */, FACF8FBE1BCC2DB10062D8F8 /* CSKLayers.m in Sources */, FA38F4BE1BC3C93F00787508 /* RegExCategories.m in Sources */, + FA795BCD1C9A8FB20050571B /* NSError+CSSketch.m in Sources */, FA56F7E01BC0DDE7005673E0 /* CSKFileMonitor.m in Sources */, FA0E95DB1BCB279C00CDD8EF /* NSString+Paths.m in Sources */, FA38F4B41BC3272100787508 /* CSKToolbarProxy.m in Sources */, diff --git a/CSSketch Helper/src/Categories/NSError+CSSketch.h b/CSSketch Helper/src/Categories/NSError+CSSketch.h new file mode 100644 index 0000000..39a3414 --- /dev/null +++ b/CSSketch Helper/src/Categories/NSError+CSSketch.h @@ -0,0 +1,15 @@ +// +// NSError+CSSketch.h +// CSSketch Helper +// +// Created by John Coates on 3/17/16. +// Copyright © 2016 John Coates. All rights reserved. +// + +#import + +@interface NSError (CSSketch) + ++ (instancetype)errorWithMessage:(NSString *)message; + +@end diff --git a/CSSketch Helper/src/Categories/NSError+CSSketch.m b/CSSketch Helper/src/Categories/NSError+CSSketch.m new file mode 100644 index 0000000..eac2b8c --- /dev/null +++ b/CSSketch Helper/src/Categories/NSError+CSSketch.m @@ -0,0 +1,27 @@ +// +// NSError+CSSketch.m +// CSSketch Helper +// +// Created by John Coates on 3/17/16. +// Copyright © 2016 John Coates. All rights reserved. +// + +#import "NSError+CSSketch.h" + +@implementation NSError (CSSketch) + ++ (instancetype)errorWithMessage:(NSString *)message { + NSError *error; + NSDictionary *userInfo; + + userInfo = @{ + NSLocalizedDescriptionKey : message + }; + error = [NSError errorWithDomain:@"CSK" + code:801 + userInfo:userInfo]; + + return error; +} + +@end diff --git a/CSSketch Helper/src/Controllers/CSKStylesheet.m b/CSSketch Helper/src/Controllers/CSKStylesheet.m index dd72f74..0c6d31b 100644 --- a/CSSketch Helper/src/Controllers/CSKStylesheet.m +++ b/CSSketch Helper/src/Controllers/CSKStylesheet.m @@ -71,14 +71,14 @@ - (BOOL)parseStylesheet:(CSKStylesheetCompiled)completionBlock { if ([CSKMainController inSandbox]) { [self.fileURL startAccessingSecurityScopedResource]; } - NSString *lessStylesheet = [NSString stringWithContentsOfFile:self.fileURL.path encoding:NSUTF8StringEncoding error:&error]; + NSString *stylesheet = [NSString stringWithContentsOfFile:self.fileURL.path encoding:NSUTF8StringEncoding error:&error]; if ([CSKMainController inSandbox]) { [self.fileURL stopAccessingSecurityScopedResource]; } if (error) { - NSLog(@"error retrieving contents of Less stylesheet: %@", error); + NSLog(@"error retrieving contents of stylesheet: %@", error); NSString *errorString = [NSString stringWithFormat:@"Couldn't read stylesheet %@", self.fileURL.path]; [CSKMainController displayError:errorString]; return FALSE; @@ -87,7 +87,7 @@ - (BOOL)parseStylesheet:(CSKStylesheetCompiled)completionBlock { // process @import // un-escaped regex: @import[\s]+?(\([^)]+\)[\s]+)?['"]?([^'"\n]+)['"]?;? // targetting: @import (keyword) "filename"; - NSArray *importMatches = [lessStylesheet matchesWithDetails:RX(@"@import[\\s]+?(\\([^)]+\\)[\\s]+)?['\"]([^'\"\\n]+)['\"]?;?")]; + NSArray *importMatches = [stylesheet matchesWithDetails:RX(@"@import[\\s]+?(\\([^)]+\\)[\\s]+)?['\"]([^'\"\\n]+)['\"]?;?")]; if (importMatches.count) { for (RxMatch *match in importMatches) { @@ -109,7 +109,7 @@ - (BOOL)parseStylesheet:(CSKStylesheetCompiled)completionBlock { [CSKMainController displayError:errorString]; return FALSE; } - lessStylesheet = [lessStylesheet stringByReplacingOccurrencesOfString:wholeMatch.value withString:importContents]; + stylesheet = [stylesheet stringByReplacingOccurrencesOfString:wholeMatch.value withString:importContents]; } else { @@ -122,15 +122,21 @@ - (BOOL)parseStylesheet:(CSKStylesheetCompiled)completionBlock { } if (DEBUG) { - NSLog(@"less stylesheet: %@", lessStylesheet); + NSLog(@"stylesheet length %d: %@", (int)stylesheet.length, stylesheet); + } + if (stylesheet.length == 0) { + completionBlock(nil, stylesheet); + return TRUE; } NSString *extension = [self fileURL].path.pathExtension.lowercaseString; if ([extension isEqualToString:@"less"]) { - [CSKLess compileLessStylesheet:lessStylesheet completion:^(NSError *error, NSString *compiledCSS) { + [CSKLess compileLessStylesheet:stylesheet completion:^(NSError *error, NSString *compiledCSS) { if (error) { - NSLog(@"error compiling stylesheet: %@", error); + NSString *errorMessage = [NSString stringWithFormat:@"CSSketch: Error compiling {less} stylesheet: %@", error]; + [CSKMainController displayError:errorMessage]; + NSLog(@"%@", errorMessage); } if (DEBUG) { @@ -144,10 +150,11 @@ - (BOOL)parseStylesheet:(CSKStylesheetCompiled)completionBlock { else if ([extension isEqualToString:@"sass"] || [extension isEqualToString:@"scss"]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ NSError *error = nil; - NSString *compiledCSS = [CocoaSass compileSass:lessStylesheet extension:extension error:&error]; + NSString *compiledCSS = [CocoaSass compileSass:stylesheet + extension:extension + error:&error]; if (error != nil || !compiledCSS) { - NSLog(@"Error compiling Sass stylesheet: %@", error); compiledCSS = @""; } @@ -161,7 +168,7 @@ - (BOOL)parseStylesheet:(CSKStylesheetCompiled)completionBlock { }); } else { - completionBlock(nil, lessStylesheet); + completionBlock(nil, stylesheet); } return TRUE; diff --git a/CSSketch Helper/src/Headers/PrefixHeader.pch b/CSSketch Helper/src/Headers/PrefixHeader.pch index 2e7f138..4d3db9e 100644 --- a/CSSketch Helper/src/Headers/PrefixHeader.pch +++ b/CSSketch Helper/src/Headers/PrefixHeader.pch @@ -23,6 +23,9 @@ // Sass #import "CocoaSass.h" +// Errors +#import "NSError+CSSketch.h" + #ifdef DEBUG #define DEBUG 1 #else diff --git a/External/CocoaSass/CocoaSass/CocoaSass.m b/External/CocoaSass/CocoaSass/CocoaSass.m index 54de8b7..89df986 100644 --- a/External/CocoaSass/CocoaSass/CocoaSass.m +++ b/External/CocoaSass/CocoaSass/CocoaSass.m @@ -40,12 +40,9 @@ + (NSString *)compileSass:(NSString *)contents sass_compiler_execute(compiler); int errorStatus = sass_context_get_error_status((struct Sass_Context *)context); - if (errorStatus) { const char *errorMessage = sass_context_get_error_message((struct Sass_Context *)context); - NSError *error; NSString *errorString; - NSDictionary *userInfo; if (errorMessage) { errorString = [NSString stringWithFormat:@"Error compiling Sass #%d: %s", @@ -56,22 +53,39 @@ + (NSString *)compileSass:(NSString *)contents errorString = [NSString stringWithFormat:@"Error compiling Sass #%d", errorStatus]; } - userInfo = @{ - NSLocalizedDescriptionKey : errorString - }; - error = [NSError errorWithDomain:@"CSK" - code:801 - userInfo:userInfo]; - - *errorOut = error; + *errorOut = [self errorWithMessage:errorString]; + sass_delete_compiler(compiler); return nil; } const char *output = sass_context_get_output_string((struct Sass_Context *)context); + if (!output) { + NSString *errorString = [NSString stringWithFormat:@"Couldn't generate Sass output. Error code (%d)", errorStatus]; + *errorOut = [self errorWithMessage:errorString]; + NSLog(@"%@", errorString); + sass_delete_compiler(compiler); + return nil; + + } NSString *compiledContents = [NSString stringWithUTF8String:output]; sass_delete_compiler(compiler); return compiledContents; } ++ (NSError *)errorWithMessage:(NSString *)message { + NSError *error; + NSDictionary *userInfo; + + userInfo = @{ + NSLocalizedDescriptionKey : message + }; + error = [NSError errorWithDomain:@"CSKSass" + code:801 + userInfo:userInfo]; + + return error; +} + + @end