From 9343ff75bcb55f4511a44780ac9ab0c498469b6a Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Tue, 3 Sep 2024 15:04:48 -0700 Subject: [PATCH 1/4] Support deprecation options in the legacy JS API (#312) --- jest.config.ts | 1 + lib/src/legacy/index.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/jest.config.ts b/jest.config.ts index c6178f0e..611e2ca5 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,4 +1,5 @@ const config = { + roots: ['/lib/', '/test/'], preset: 'ts-jest', testEnvironment: 'node', }; diff --git a/lib/src/legacy/index.ts b/lib/src/legacy/index.ts index f5467565..65e6c937 100644 --- a/lib/src/legacy/index.ts +++ b/lib/src/legacy/index.ts @@ -171,6 +171,9 @@ function convertOptions( verbose: options.verbose, charset: options.charset, logger: options.logger, + fatalDeprecations: options.fatalDeprecations, + futureDeprecations: options.futureDeprecations, + silenceDeprecations: options.silenceDeprecations, legacy: true, }; } From 80a503895b20b44263e7f3b7ce60bd6eb4dc458e Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 3 Sep 2024 23:04:21 +0000 Subject: [PATCH 2/4] Update Dart Sass version and release --- CHANGELOG.md | 39 +++++++++++++++++++++++ npm/android-arm/package.json | 2 +- npm/android-arm64/package.json | 2 +- npm/android-ia32/package.json | 2 +- npm/android-riscv64/package.json | 2 +- npm/android-x64/package.json | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ia32/package.json | 2 +- npm/linux-musl-arm/package.json | 2 +- npm/linux-musl-arm64/package.json | 2 +- npm/linux-musl-ia32/package.json | 2 +- npm/linux-musl-riscv64/package.json | 2 +- npm/linux-musl-x64/package.json | 2 +- npm/linux-riscv64/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 48 +++++++++++++++-------------- 22 files changed, 84 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8533ae1c..7c1bc6a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +## 1.78.0 + +* The `meta.feature-exists` function is now deprecated. This deprecation is + named `feature-exists`. + +* Fix a crash when using `@at-root` without any queries or children in the + indented syntax. + +### JS API + +* Backport the deprecation options (`fatalDeprecations`, `futureDeprecations`, + and `silenceDeprecations`) to the legacy JS API. The legacy JS API is itself + deprecated, and you should move off of it if possible, but this will allow + users of bundlers and other tools that are still using the legacy API to + still control deprecation warnings. + +* Fix a bug where accessing `SourceSpan.url` would crash when a relative URL was + passed to the Sass API. + +### Embedded Sass + +* Explicitly expose a `sass` executable from the `sass-embedded` npm package. + This was intended to be included in 1.63.0, but due to the way + platform-specific dependency executables are installed it did not work as + intended. Now users can run `npx sass` for local installs or just `sass` when + `sass-embedded` is installed globally. + +* Add linux-riscv64, linux-musl-riscv64, and android-riscv64 support for the + `sass-embedded` npm package. + +* Fix an edge case where the Dart VM could hang when shutting down when requests + were in flight. + +* Fix a race condition where the embedded host could fail to shut down if it was + closed around the same time a new compilation was started. + +* Fix a bug where parse-time deprecation warnings could not be controlled by + the deprecation options in some circumstances. + ## 1.77.8 * No user-visible changes. diff --git a/npm/android-arm/package.json b/npm/android-arm/package.json index 8d467a14..45d8d4b1 100644 --- a/npm/android-arm/package.json +++ b/npm/android-arm/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-android-arm", - "version": "1.77.8", + "version": "1.78.0", "description": "The android-arm binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/android-arm64/package.json b/npm/android-arm64/package.json index 6648630f..b7a30063 100644 --- a/npm/android-arm64/package.json +++ b/npm/android-arm64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-android-arm64", - "version": "1.77.8", + "version": "1.78.0", "description": "The android-arm64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/android-ia32/package.json b/npm/android-ia32/package.json index 4d9c9bc4..1b2b17a5 100644 --- a/npm/android-ia32/package.json +++ b/npm/android-ia32/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-android-ia32", - "version": "1.77.8", + "version": "1.78.0", "description": "The android-ia32 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/android-riscv64/package.json b/npm/android-riscv64/package.json index 7096a34d..46f22303 100644 --- a/npm/android-riscv64/package.json +++ b/npm/android-riscv64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-android-riscv64", - "version": "1.77.8", + "version": "1.78.0", "description": "The android-riscv64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/android-x64/package.json b/npm/android-x64/package.json index 598f2308..226e6d6a 100644 --- a/npm/android-x64/package.json +++ b/npm/android-x64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-android-x64", - "version": "1.77.8", + "version": "1.78.0", "description": "The android-x64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 08a81de6..91b979c0 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-darwin-arm64", - "version": "1.77.8", + "version": "1.78.0", "description": "The darwin-arm64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index e3428f50..a40c73f5 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-darwin-x64", - "version": "1.77.8", + "version": "1.78.0", "description": "The darwin-x64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index dd910307..d5980124 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-arm", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-arm binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 9cd90d34..8337e3c5 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-arm64", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-arm64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-ia32/package.json b/npm/linux-ia32/package.json index 48356826..9ccccf75 100644 --- a/npm/linux-ia32/package.json +++ b/npm/linux-ia32/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-ia32", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-ia32 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-musl-arm/package.json b/npm/linux-musl-arm/package.json index 24ace4f8..ce6589f1 100644 --- a/npm/linux-musl-arm/package.json +++ b/npm/linux-musl-arm/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-musl-arm", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-musl-arm binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-musl-arm64/package.json b/npm/linux-musl-arm64/package.json index a1ffe55e..aadccab1 100644 --- a/npm/linux-musl-arm64/package.json +++ b/npm/linux-musl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-musl-arm64", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-musl-arm64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-musl-ia32/package.json b/npm/linux-musl-ia32/package.json index 60746951..920bd4f8 100644 --- a/npm/linux-musl-ia32/package.json +++ b/npm/linux-musl-ia32/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-musl-ia32", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-musl-ia32 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-musl-riscv64/package.json b/npm/linux-musl-riscv64/package.json index c4cd9bbc..252604dc 100644 --- a/npm/linux-musl-riscv64/package.json +++ b/npm/linux-musl-riscv64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-musl-riscv64", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-musl-riscv64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-musl-x64/package.json b/npm/linux-musl-x64/package.json index ac4afa94..de457038 100644 --- a/npm/linux-musl-x64/package.json +++ b/npm/linux-musl-x64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-musl-x64", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-musl-x64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-riscv64/package.json b/npm/linux-riscv64/package.json index 332e08b5..89fb5220 100644 --- a/npm/linux-riscv64/package.json +++ b/npm/linux-riscv64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-riscv64", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-riscv64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 308a38fb..764107ac 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-linux-x64", - "version": "1.77.8", + "version": "1.78.0", "description": "The linux-x64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 27a53b3b..659beec2 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-win32-arm64", - "version": "1.77.8", + "version": "1.78.0", "description": "The win32-arm64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 97b1df67..80b816ee 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-win32-ia32", - "version": "1.77.8", + "version": "1.78.0", "description": "The win32-ia32 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 5ecbe218..79e7c609 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "sass-embedded-win32-x64", - "version": "1.77.8", + "version": "1.78.0", "description": "The win32-x64 binary for sass-embedded", "repository": "sass/embedded-host-node", "author": "Google Inc.", diff --git a/package.json b/package.json index 1858b8ce..3f4a9919 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "sass-embedded", - "version": "1.77.8", + "version": "1.78.0", "protocol-version": "2.7.1", - "compiler-version": "1.77.8", + "compiler-version": "1.78.0", "description": "Node.js library that communicates with Embedded Dart Sass using the Embedded Sass protocol", "repository": "sass/embedded-host-node", "author": "Google Inc.", @@ -23,7 +23,9 @@ "engines": { "node": ">=16.0.0" }, - "bin": {"sass": "dist/bin/sass.js"}, + "bin": { + "sass": "dist/bin/sass.js" + }, "scripts": { "init": "ts-node ./tool/init.ts", "check": "npm-run-all check:gts check:tsc", @@ -36,26 +38,26 @@ "test": "jest" }, "optionalDependencies": { - "sass-embedded-android-arm": "1.77.8", - "sass-embedded-android-arm64": "1.77.8", - "sass-embedded-android-ia32": "1.77.8", - "sass-embedded-android-riscv64": "1.77.8", - "sass-embedded-android-x64": "1.77.8", - "sass-embedded-darwin-arm64": "1.77.8", - "sass-embedded-darwin-x64": "1.77.8", - "sass-embedded-linux-arm": "1.77.8", - "sass-embedded-linux-arm64": "1.77.8", - "sass-embedded-linux-ia32": "1.77.8", - "sass-embedded-linux-riscv64": "1.77.8", - "sass-embedded-linux-x64": "1.77.8", - "sass-embedded-linux-musl-arm": "1.77.8", - "sass-embedded-linux-musl-arm64": "1.77.8", - "sass-embedded-linux-musl-ia32": "1.77.8", - "sass-embedded-linux-musl-riscv64": "1.77.8", - "sass-embedded-linux-musl-x64": "1.77.8", - "sass-embedded-win32-arm64": "1.77.8", - "sass-embedded-win32-ia32": "1.77.8", - "sass-embedded-win32-x64": "1.77.8" + "sass-embedded-android-arm": "1.78.0", + "sass-embedded-android-arm64": "1.78.0", + "sass-embedded-android-ia32": "1.78.0", + "sass-embedded-android-riscv64": "1.78.0", + "sass-embedded-android-x64": "1.78.0", + "sass-embedded-darwin-arm64": "1.78.0", + "sass-embedded-darwin-x64": "1.78.0", + "sass-embedded-linux-arm": "1.78.0", + "sass-embedded-linux-arm64": "1.78.0", + "sass-embedded-linux-ia32": "1.78.0", + "sass-embedded-linux-riscv64": "1.78.0", + "sass-embedded-linux-x64": "1.78.0", + "sass-embedded-linux-musl-arm": "1.78.0", + "sass-embedded-linux-musl-arm64": "1.78.0", + "sass-embedded-linux-musl-ia32": "1.78.0", + "sass-embedded-linux-musl-riscv64": "1.78.0", + "sass-embedded-linux-musl-x64": "1.78.0", + "sass-embedded-win32-arm64": "1.78.0", + "sass-embedded-win32-ia32": "1.78.0", + "sass-embedded-win32-x64": "1.78.0" }, "dependencies": { "@bufbuild/protobuf": "^1.0.0", From 9076adb87cd6589fc6b1ff06bc320309c36b0293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 5 Sep 2024 16:04:29 -0700 Subject: [PATCH 3/4] Fix race condition in SyncMessagePort (#327) Co-authored-by: Natalie Weizenbaum --- .../sync-process/sync-message-port.test.ts | 19 +++++++++++++++++++ lib/src/sync-process/sync-message-port.ts | 18 +++++++++++------- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/src/sync-process/sync-message-port.test.ts b/lib/src/sync-process/sync-message-port.test.ts index 3a082d00..4c1e1674 100644 --- a/lib/src/sync-process/sync-message-port.test.ts +++ b/lib/src/sync-process/sync-message-port.test.ts @@ -36,6 +36,7 @@ describe('SyncMessagePort', () => { ); expect(port.receiveMessage()).toEqual('done!'); + expect(port.receiveMessage).toThrow(); }); it('multiple times before the other endpoint starts reading', () => { @@ -52,6 +53,24 @@ describe('SyncMessagePort', () => { expect(port2.receiveMessage()).toEqual('message3'); expect(port2.receiveMessage()).toEqual('message4'); }); + + it('multiple times and close', () => { + const channel = SyncMessagePort.createChannel(); + const port = new SyncMessagePort(channel.port1); + + spawnWorker( + ` + port.postMessage('message1'); + port.postMessage('done!'); + port.close(); + `, + channel.port2 + ); + + expect(port.receiveMessage()).toEqual('message1'); + expect(port.receiveMessage()).toEqual('done!'); + expect(port.receiveMessage).toThrow(); + }); }); describe('with an asynchronous listener', () => { diff --git a/lib/src/sync-process/sync-message-port.ts b/lib/src/sync-process/sync-message-port.ts index 7c82a343..7970244e 100644 --- a/lib/src/sync-process/sync-message-port.ts +++ b/lib/src/sync-process/sync-message-port.ts @@ -23,18 +23,19 @@ enum BufferState { * the buffer to this state so that it can use `Atomics.wait()` to be notified * when it switches to `MessageSent`. */ - AwaitingMessage, + AwaitingMessage = 0b00, /** * The state indicating that a message has been sent. Whenever an endpoint * sends a message, it'll set the buffer to this state so that the other * endpoint's `Atomics.wait()` call terminates. */ - MessageSent, + MessageSent = 0b01, /** - * The state indicating that the channel has been closed. This never - * transitions to any other states. + * The bitmask indicating that the channel has been closed. This is masked on + * top of AwaitingMessage and MessageSent state. It never transitions to any + * other states once closed. */ - Closed, + Closed = 0b10, } /** @@ -158,13 +159,16 @@ export class SyncMessagePort extends EventEmitter { message = receiveMessageOnPort(this.port); if (message) return message.message; - assert.equal(Atomics.load(this.buffer, 0), BufferState.Closed); + // Update the state to 0b10 after the last message is consumed. + const oldState = Atomics.and(this.buffer, 0, BufferState.Closed); + // Assert the old state was either 0b10 or 0b11. + assert.equal(oldState & BufferState.Closed, BufferState.Closed); throw new Error("The SyncMessagePort's channel is closed."); } /** See `MessagePort.close()`. */ close(): void { - Atomics.store(this.buffer, 0, BufferState.Closed); + Atomics.or(this.buffer, 0, BufferState.Closed); this.port.close(); } } From 71004ad52d3861626a02ad6ab97012ab811540f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Fri, 6 Sep 2024 19:50:39 -0700 Subject: [PATCH 4/4] Upgrade protobuf-es to 2.0.0 (#328) --- lib/src/compiler/utils.ts | 15 ++++-- lib/src/dispatcher.ts | 5 +- lib/src/function-registry.ts | 5 +- lib/src/importer-registry.ts | 41 ++++++++------- lib/src/message-transformer.test.ts | 21 +++++--- lib/src/message-transformer.ts | 13 +++-- lib/src/protofier.ts | 78 +++++++++++++---------------- package.json | 6 +-- 8 files changed, 100 insertions(+), 84 deletions(-) diff --git a/lib/src/compiler/utils.ts b/lib/src/compiler/utils.ts index 80e1e0fc..f04f03fc 100644 --- a/lib/src/compiler/utils.ts +++ b/lib/src/compiler/utils.ts @@ -4,6 +4,8 @@ import * as p from 'path'; import * as supportsColor from 'supports-color'; +import {create} from '@bufbuild/protobuf'; + import {Deprecation, deprecations, getDeprecationIds} from '../deprecations'; import {deprotofySourceSpan} from '../deprotofy-span'; import {Dispatcher, DispatcherHandlers} from '../dispatcher'; @@ -65,7 +67,7 @@ function newCompileRequest( importers: ImporterRegistry<'sync' | 'async'>, options?: Options<'sync' | 'async'> ): proto.InboundMessage_CompileRequest { - const request = new proto.InboundMessage_CompileRequest({ + const request = create(proto.InboundMessage_CompileRequestSchema, { importers: importers.importers, globalFunctions: Object.keys(options?.functions ?? {}), sourceMap: !!options?.sourceMap, @@ -115,7 +117,7 @@ export function newCompileStringRequest( importers: ImporterRegistry<'sync' | 'async'>, options?: StringOptions<'sync' | 'async'> ): proto.InboundMessage_CompileRequest { - const input = new proto.InboundMessage_CompileRequest_StringInput({ + const input = create(proto.InboundMessage_CompileRequest_StringInputSchema, { source, syntax: utils.protofySyntax(options?.syntax ?? 'scss'), }); @@ -128,9 +130,12 @@ export function newCompileStringRequest( if (options && 'importer' in options && options.importer) { input.importer = importers.register(options.importer); } else if (url === legacyImporterProtocol) { - input.importer = new proto.InboundMessage_CompileRequest_Importer({ - importer: {case: 'path', value: p.resolve('.')}, - }); + input.importer = create( + proto.InboundMessage_CompileRequest_ImporterSchema, + { + importer: {case: 'path', value: p.resolve('.')}, + } + ); } else { // When importer is not set on the host, the compiler will set a // FileSystemImporter if `url` is set to a file: url or a NoOpImporter. diff --git a/lib/src/dispatcher.ts b/lib/src/dispatcher.ts index 48cafefb..00cf9bc1 100644 --- a/lib/src/dispatcher.ts +++ b/lib/src/dispatcher.ts @@ -4,6 +4,7 @@ import {Observable, Subject} from 'rxjs'; import {filter, map, mergeMap, takeUntil} from 'rxjs/operators'; +import {create} from '@bufbuild/protobuf'; import {OutboundResponse} from './messages'; import * as proto from './vendor/embedded_sass_pb'; @@ -144,7 +145,7 @@ export class Dispatcher { try { this.writeInboundMessage([ this.compilationId, - new proto.InboundMessage({ + create(proto.InboundMessageSchema, { message: {value: request, case: 'compileRequest'}, }), ]); @@ -267,7 +268,7 @@ export class Dispatcher { this.writeInboundMessage([ this.compilationId, - new proto.InboundMessage({message}), + create(proto.InboundMessageSchema, {message}), ]); } } diff --git a/lib/src/function-registry.ts b/lib/src/function-registry.ts index 0c4a3b81..c9921205 100644 --- a/lib/src/function-registry.ts +++ b/lib/src/function-registry.ts @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. import {inspect} from 'util'; +import {create} from '@bufbuild/protobuf'; import * as types from './vendor/sass'; import * as utils from './utils'; @@ -74,7 +75,7 @@ export class FunctionRegistry { ); } - return new proto.InboundMessage_FunctionCallResponse({ + return create(proto.InboundMessage_FunctionCallResponseSchema, { result: {case: 'success', value: protofier.protofy(result)}, accessedArgumentLists: protofier.accessedArgumentLists, }); @@ -82,7 +83,7 @@ export class FunctionRegistry { ); }, error => - new proto.InboundMessage_FunctionCallResponse({ + create(proto.InboundMessage_FunctionCallResponseSchema, { result: {case: 'error', value: `${error}`}, }) ); diff --git a/lib/src/importer-registry.ts b/lib/src/importer-registry.ts index 691b4af2..085ca4b0 100644 --- a/lib/src/importer-registry.ts +++ b/lib/src/importer-registry.ts @@ -6,6 +6,7 @@ import {createRequire} from 'module'; import * as p from 'path'; import {URL} from 'url'; import {inspect} from 'util'; +import {create} from '@bufbuild/protobuf'; import {CanonicalizeContext} from './canonicalize-context'; import * as utils from './utils'; @@ -64,11 +65,10 @@ export class ImporterRegistry { ) ) .concat( - (options?.loadPaths ?? []).map( - path => - new proto.InboundMessage_CompileRequest_Importer({ - importer: {case: 'path', value: p.resolve(path)}, - }) + (options?.loadPaths ?? []).map(path => + create(proto.InboundMessage_CompileRequest_ImporterSchema, { + importer: {case: 'path', value: p.resolve(path)}, + }) ) ); } @@ -77,10 +77,14 @@ export class ImporterRegistry { register( importer: Importer | FileImporter | NodePackageImporter ): proto.InboundMessage_CompileRequest_Importer { - const message = new proto.InboundMessage_CompileRequest_Importer(); + const message = create( + proto.InboundMessage_CompileRequest_ImporterSchema, + {} + ); if (importer instanceof NodePackageImporter) { - const importerMessage = new proto.NodePackageImporter(); - importerMessage.entryPointDirectory = importer[entryPointDirectoryKey]; + const importerMessage = create(proto.NodePackageImporterSchema, { + entryPointDirectory: importer[entryPointDirectoryKey], + }); message.importer = { case: 'nodePackageImporter', value: importerMessage, @@ -126,7 +130,7 @@ export class ImporterRegistry { return thenOr( importer.canonicalize(request.url, canonicalizeContext), url => - new proto.InboundMessage_CanonicalizeResponse({ + create(proto.InboundMessage_CanonicalizeResponseSchema, { result: url === null ? {case: undefined} @@ -136,7 +140,7 @@ export class ImporterRegistry { ); }, error => - new proto.InboundMessage_CanonicalizeResponse({ + create(proto.InboundMessage_CanonicalizeResponseSchema, { result: {case: 'error', value: `${error}`}, }) ); @@ -154,7 +158,8 @@ export class ImporterRegistry { return catchOr( () => { return thenOr(importer.load(new URL(request.url)), result => { - if (!result) return new proto.InboundMessage_ImportResponse(); + if (!result) + return create(proto.InboundMessage_ImportResponseSchema, {}); if (typeof result.contents !== 'string') { throw Error( @@ -171,20 +176,20 @@ export class ImporterRegistry { ); } - return new proto.InboundMessage_ImportResponse({ + return create(proto.InboundMessage_ImportResponseSchema, { result: { case: 'success', - value: new proto.InboundMessage_ImportResponse_ImportSuccess({ + value: { contents: result.contents, syntax: utils.protofySyntax(result.syntax), sourceMapUrl: result.sourceMapUrl?.toString() ?? '', - }), + }, }, }); }); }, error => - new proto.InboundMessage_ImportResponse({ + create(proto.InboundMessage_ImportResponseSchema, { result: {case: 'error', value: `${error}`}, }) ); @@ -210,7 +215,7 @@ export class ImporterRegistry { importer.findFileUrl(request.url, canonicalizeContext), url => { if (!url) { - return new proto.InboundMessage_FileImportResponse({ + return create(proto.InboundMessage_FileImportResponseSchema, { containingUrlUnused: !canonicalizeContext.containingUrlAccessed, }); } @@ -220,7 +225,7 @@ export class ImporterRegistry { +`"${url}" for URL "${request.url}".` ); } - return new proto.InboundMessage_FileImportResponse({ + return create(proto.InboundMessage_FileImportResponseSchema, { result: {case: 'fileUrl', value: url.toString()}, containingUrlUnused: !canonicalizeContext.containingUrlAccessed, }); @@ -228,7 +233,7 @@ export class ImporterRegistry { ); }, error => - new proto.InboundMessage_FileImportResponse({ + create(proto.InboundMessage_FileImportResponseSchema, { result: {case: 'error', value: `${error}`}, }) ); diff --git a/lib/src/message-transformer.test.ts b/lib/src/message-transformer.test.ts index 767999c9..7053139b 100644 --- a/lib/src/message-transformer.test.ts +++ b/lib/src/message-transformer.test.ts @@ -4,6 +4,7 @@ import {Observable, Subject} from 'rxjs'; import * as varint from 'varint'; +import {create, toBinary} from '@bufbuild/protobuf'; import {expectObservableToError} from '../../test/utils'; import {MessageTransformer} from './message-transformer'; @@ -13,17 +14,17 @@ describe('message transformer', () => { let messages: MessageTransformer; function validInboundMessage(source: string): proto.InboundMessage { - return new proto.InboundMessage({ + return create(proto.InboundMessageSchema, { message: { case: 'compileRequest', - value: new proto.InboundMessage_CompileRequest({ + value: { input: { case: 'string', - value: new proto.InboundMessage_CompileRequest_StringInput({ + value: { source, - }), + }, }, - }), + }, }, }); } @@ -42,7 +43,10 @@ describe('message transformer', () => { const message = validInboundMessage('a {b: c}'); messages.writeInboundMessage([1234, message]); expect(encodedProtobufs).toEqual([ - Uint8Array.from([...varint.encode(1234), ...message.toBinary()]), + Uint8Array.from([ + ...varint.encode(1234), + ...toBinary(proto.InboundMessageSchema, message), + ]), ]); }); }); @@ -81,7 +85,10 @@ describe('message transformer', () => { protobufs$.next( Uint8Array.from([ ...varint.encode(1234), - ...validInboundMessage('a {b: c}').toBinary(), + ...toBinary( + proto.InboundMessageSchema, + validInboundMessage('a {b: c}') + ), ]) ); protobufs$.complete(); diff --git a/lib/src/message-transformer.ts b/lib/src/message-transformer.ts index e7d00023..dd508396 100644 --- a/lib/src/message-transformer.ts +++ b/lib/src/message-transformer.ts @@ -4,10 +4,16 @@ import {Observable, Subject} from 'rxjs'; import {map} from 'rxjs/operators'; +import {fromBinary, toBinary} from '@bufbuild/protobuf'; import * as varint from 'varint'; import {compilerError} from './utils'; -import {InboundMessage, OutboundMessage} from './vendor/embedded_sass_pb'; +import { + InboundMessage, + InboundMessageSchema, + OutboundMessage, + OutboundMessageSchema, +} from './vendor/embedded_sass_pb'; /** * Encodes InboundMessages into protocol buffers and decodes protocol buffers @@ -43,7 +49,7 @@ export class MessageTransformer { InboundMessage, ]): void { const compilationIdLength = varint.encodingLength(compilationId); - const encodedMessage = message.toBinary(); + const encodedMessage = toBinary(InboundMessageSchema, message); const buffer = new Uint8Array(compilationIdLength + encodedMessage.length); varint.encode(compilationId, buffer); buffer.set(encodedMessage, compilationIdLength); @@ -71,7 +77,8 @@ function decode(buffer: Uint8Array): [number, OutboundMessage] { try { return [ compilationId, - OutboundMessage.fromBinary( + fromBinary( + OutboundMessageSchema, new Uint8Array(buffer.buffer, varint.decode.bytes) ), ]; diff --git a/lib/src/protofier.ts b/lib/src/protofier.ts index 00fa3c52..43e43487 100644 --- a/lib/src/protofier.ts +++ b/lib/src/protofier.ts @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. import {OrderedMap} from 'immutable'; +import {create} from '@bufbuild/protobuf'; import * as proto from './vendor/embedded_sass_pb'; import * as utils from './utils'; @@ -57,72 +58,61 @@ export class Protofier { /** Converts `value` to its protocol buffer representation. */ protofy(value: Value): proto.Value { - const result = new proto.Value(); + const result = create(proto.ValueSchema, {}); if (value instanceof SassString) { - const string = new proto.Value_String(); - string.text = value.text; - string.quoted = value.hasQuotes; + const string = create(proto.Value_StringSchema, { + text: value.text, + quoted: value.hasQuotes, + }); result.value = {case: 'string', value: string}; } else if (value instanceof SassNumber) { result.value = {case: 'number', value: this.protofyNumber(value)}; } else if (value instanceof SassColor) { if (value.hasCalculatedHsl) { - const color = new proto.Value_HslColor(); - color.hue = value.hue; - color.saturation = value.saturation; - color.lightness = value.lightness; - color.alpha = value.alpha; + const color = create(proto.Value_HslColorSchema, value); result.value = {case: 'hslColor', value: color}; } else { - const color = new proto.Value_RgbColor(); - color.red = value.red; - color.green = value.green; - color.blue = value.blue; - color.alpha = value.alpha; + const color = create(proto.Value_RgbColorSchema, value); result.value = {case: 'rgbColor', value: color}; } } else if (value instanceof SassList) { - const list = new proto.Value_List(); - list.separator = this.protofySeparator(value.separator); - list.hasBrackets = value.hasBrackets; - for (const element of value.asList) { - list.contents.push(this.protofy(element)); - } + const list = create(proto.Value_ListSchema, { + separator: this.protofySeparator(value.separator), + hasBrackets: value.hasBrackets, + contents: value.asList.map(element => this.protofy(element)).toArray(), + }); result.value = {case: 'list', value: list}; } else if (value instanceof SassArgumentList) { - const list = new proto.Value_ArgumentList(); - list.id = value.id; - list.separator = this.protofySeparator(value.separator); - list.contents = value.asList - .map(element => this.protofy(element)) - .toArray(); + const list = create(proto.Value_ArgumentListSchema, { + id: value.id, + separator: this.protofySeparator(value.separator), + contents: value.asList.map(element => this.protofy(element)).toArray(), + }); for (const [key, mapValue] of value.keywordsInternal) { list.keywords[key] = this.protofy(mapValue); } result.value = {case: 'argumentList', value: list}; } else if (value instanceof SassMap) { - const map = new proto.Value_Map(); - for (const [key, mapValue] of value.contents) { - const entry = new proto.Value_Map_Entry(); - entry.key = this.protofy(key); - entry.value = this.protofy(mapValue); - map.entries.push(entry); - } + const map = create(proto.Value_MapSchema, { + entries: value.contents.toArray().map(([key, value]) => ({ + key: this.protofy(key), + value: this.protofy(value), + })), + }); result.value = {case: 'map', value: map}; } else if (value instanceof SassFunction) { if (value.id !== undefined) { - const fn = new proto.Value_CompilerFunction(); - fn.id = value.id; + const fn = create(proto.Value_CompilerFunctionSchema, value); result.value = {case: 'compilerFunction', value: fn}; } else { - const fn = new proto.Value_HostFunction(); - fn.id = this.functions.register(value.callback!); - fn.signature = value.signature!; + const fn = create(proto.Value_HostFunctionSchema, { + id: this.functions.register(value.callback!), + signature: value.signature!, + }); result.value = {case: 'hostFunction', value: fn}; } } else if (value instanceof SassMixin) { - const mixin = new proto.Value_CompilerMixin(); - mixin.id = value.id; + const mixin = create(proto.Value_CompilerMixinSchema, value); result.value = {case: 'compilerMixin', value: mixin}; } else if (value instanceof SassCalculation) { result.value = { @@ -143,7 +133,7 @@ export class Protofier { /** Converts `number` to its protocol buffer representation. */ private protofyNumber(number: SassNumber): proto.Value_Number { - return new proto.Value_Number({ + return create(proto.Value_NumberSchema, { value: number.value, numerators: number.numeratorUnits.toArray(), denominators: number.denominatorUnits.toArray(), @@ -170,7 +160,7 @@ export class Protofier { private protofyCalculation( calculation: SassCalculation ): proto.Value_Calculation { - return new proto.Value_Calculation({ + return create(proto.Value_CalculationSchema, { name: calculation.name, arguments: calculation.arguments .map(this.protofyCalculationValue.bind(this)) @@ -183,7 +173,7 @@ export class Protofier { private protofyCalculationValue( value: Object ): proto.Value_Calculation_CalculationValue { - const result = new proto.Value_Calculation_CalculationValue(); + const result = create(proto.Value_Calculation_CalculationValueSchema, {}); if (value instanceof SassCalculation) { result.value = { case: 'calculation', @@ -192,7 +182,7 @@ export class Protofier { } else if (value instanceof CalculationOperation) { result.value = { case: 'operation', - value: new proto.Value_Calculation_CalculationOperation({ + value: create(proto.Value_Calculation_CalculationOperationSchema, { operator: this.protofyCalculationOperator(value.operator), left: this.protofyCalculationValue(value.left), right: this.protofyCalculationValue(value.right), diff --git a/package.json b/package.json index 3f4a9919..c04912fb 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "sass-embedded-win32-x64": "1.78.0" }, "dependencies": { - "@bufbuild/protobuf": "^1.0.0", + "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "immutable": "^4.0.0", "rxjs": "^7.4.0", @@ -68,8 +68,8 @@ "varint": "^6.0.0" }, "devDependencies": { - "@bufbuild/buf": "^1.13.1-4", - "@bufbuild/protoc-gen-es": "^1.0.0", + "@bufbuild/buf": "^1.39.0", + "@bufbuild/protoc-gen-es": "^2.0.0", "@types/buffer-builder": "^0.2.0", "@types/google-protobuf": "^3.7.2", "@types/jest": "^29.4.0",