diff --git a/CHANGELOG.md b/CHANGELOG.md index 2353b2dd..cbf2f194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.0.0-beta.7 + +* Expose the `Exception` class and ensure that syntax errors match the official + JS API. + ## 1.0.0-beta.6 * Expose (as yet incomplete) `compile()`, `compileString()`, `compileAsync()`, diff --git a/lib/index.ts b/lib/index.ts index 62028e7f..65abda8d 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -13,6 +13,7 @@ export {sassNull} from './src/value/null'; export {SassNumber} from './src/value/number'; export {SassString} from './src/value/string'; +export {Exception} from './src/exception'; export { compile, compileString, diff --git a/lib/src/compile.ts b/lib/src/compile.ts index 62b2fb27..99765152 100644 --- a/lib/src/compile.ts +++ b/lib/src/compile.ts @@ -12,7 +12,7 @@ import {Dispatcher, DispatcherHandlers} from './dispatcher'; import {MessageTransformer} from './message-transformer'; import {PacketTransformer} from './packet-transformer'; import {SyncEmbeddedCompiler} from './sync-compiler'; -import {deprotofyException} from './exception'; +import {Exception} from './exception'; export function compile( path: string, @@ -257,7 +257,7 @@ function handleCompileResponse( if (sourceMap) result.sourceMap = JSON.parse(sourceMap); return result; } else if (response.getFailure()) { - throw deprotofyException(response.getFailure()!); + throw new Exception(response.getFailure()!); } else { throw Error('Compiler sent empty CompileResponse.'); } diff --git a/lib/src/exception.test.ts b/lib/src/exception.test.ts deleted file mode 100644 index 825c6d8e..00000000 --- a/lib/src/exception.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2020 Google Inc. Use of this source code is governed by an -// MIT-style license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -import {SassException} from './exception'; - -describe('SassException', () => { - it('has the correct message', () => { - try { - throw new SassException('sad', ''); - } catch (error) { - expect(error.message).toBe('sad'); - } - }); - - it('has the correct span', () => { - const span = { - text: 'text', - start: { - offset: 0, - line: 0, - column: 0, - }, - end: { - offset: 1, - line: 1, - column: 1, - }, - url: new URL('https://url'), - context: 'context', - }; - try { - throw new SassException('', '', span); - } catch (error) { - expect(error.span).toEqual(span); - } - }); - - it('has the correct trace', () => { - try { - throw new SassException('', '', undefined, 'sherlock'); - } catch (error) { - expect(error.trace).toBe('sherlock'); - } - }); - - it('has a useful toString() method', () => { - try { - throw new SassException('', 'Error: aesthetically sad'); - } catch (error) { - expect(error.toString()).toBe('Error: aesthetically sad'); - } - }); - - it('contains the Sass stack inside the JS stack', () => { - try { - throw new SassException('sad', 'Error: aesthetically\n sad'); - } catch (error) { - expect(/^Error: aesthetically\n\s\ssad\n\s+at/.test(error.stack)).toBe( - true - ); - } - }); -}); diff --git a/lib/src/exception.ts b/lib/src/exception.ts index 4697301a..ca2a2a58 100644 --- a/lib/src/exception.ts +++ b/lib/src/exception.ts @@ -3,56 +3,23 @@ // https://opensource.org/licenses/MIT. import * as proto from './vendor/embedded-protocol/embedded_sass_pb'; -import {SourceSpan} from './vendor/sass'; +import {Exception as SassException, SourceSpan} from './vendor/sass'; import {deprotofySourceSpan} from './deprotofy-span'; -/** - * An exception thrown by Sass. - */ -export class SassException extends Error { - /** - * @param message - The error message. - * @param formatted - The formatted error message. Includes the message, span, - * and trace. - * @param [span] - The source span associated with the error. - * @param [trace] - The trace associated with the error. - */ - constructor( - readonly message: string, - private readonly formatted: string, - readonly span?: SourceSpan, - readonly trace?: string - ) { - super(message); +export class Exception extends Error implements SassException { + readonly sassMessage: string; + readonly sassStack: string; + readonly span: SourceSpan; - if (formatted === '') this.formatted = `Error: ${message}`; - if (trace === '') this.trace = undefined; + constructor(failure: proto.OutboundMessage.CompileResponse.CompileFailure) { + super(failure.getFormatted()); - // Inject the entire Sass error into the JS stack trace. - this.stack = this.stack?.replace( - new RegExp(`^Error: ${message}`), - this.formatted - ); + this.sassMessage = failure.getMessage(); + this.sassStack = failure.getStackTrace(); + this.span = deprotofySourceSpan(failure.getSpan()!); } toString() { - return this.formatted; + return this.message; } } - -/** - * Creates a SassException from the given protocol `buffer`. Throws if the - * buffer has invalid fields. - */ -export function deprotofyException( - buffer: proto.OutboundMessage.CompileResponse.CompileFailure -): SassException { - const span = buffer.getSpan(); - - return new SassException( - buffer.getMessage(), - buffer.getFormatted(), - span ? deprotofySourceSpan(span) : undefined, - buffer.getStackTrace() - ); -} diff --git a/lib/src/legacy.ts b/lib/src/legacy.ts index 435c1f66..83545b73 100644 --- a/lib/src/legacy.ts +++ b/lib/src/legacy.ts @@ -5,8 +5,8 @@ import * as p from 'path'; import {URL, fileURLToPath, pathToFileURL} from 'url'; +import {Exception} from './exception'; import {compileAsync, compileStringAsync} from './compile'; -import {SassException} from './exception'; import {isNullOrUndefined, pathToUrlString, withoutExtension} from './utils'; import { CompileResult, @@ -141,8 +141,8 @@ function newLegacyResult( // Decorates an Error with additional fields so that it behaves like a Node Sass // error. -function newLegacyException(error: Error | SassException): LegacyException { - if (!(error instanceof SassException)) { +function newLegacyException(error: Error | Exception): LegacyException { + if (!(error instanceof Exception)) { return Object.assign(error, { formatted: error.toString(), status: 3, diff --git a/package.json b/package.json index 3aca81ab..a92750e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded", - "version": "1.0.0-beta.6", + "version": "1.0.0-dev", "protocol-version": "1.0.0-beta.11", "compiler-version": "1.0.0-beta.9", "description": "Node.js library that communicates with Embedded Dart Sass using the Embedded Sass protocol",