├── VERSION ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── .github └── workflows │ └── ci.yml ├── CHANGELOG.md ├── README.md └── embedded_sass.proto /VERSION: -------------------------------------------------------------------------------- 1 | 1.2.0 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Sass is more than a technology; Sass is driven by the community of individuals 2 | that power its development and use every day. As a community, we want to embrace 3 | the very differences that have made our collaboration so powerful, and work 4 | together to provide the best environment for learning, growing, and sharing of 5 | ideas. It is imperative that we keep Sass a fun, welcoming, challenging, and 6 | fair place to play. 7 | 8 | [The full community guidelines can be found on the Sass website.][link] 9 | 10 | [link]: https://sass-lang.com/community-guidelines 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Google LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main, feature.*] 6 | tags: ['**'] 7 | pull_request: 8 | 9 | jobs: 10 | protoc: 11 | name: "Validate proto" 12 | runs-on: "ubuntu-latest" 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: arduino/setup-protoc@v1 17 | with: { version: "3.x", repo-token: "${{ github.token }}" } 18 | - name: Generate protobuf code 19 | run: protoc --js_out=/tmp embedded_sass.proto 20 | 21 | versions: 22 | name: "Validate versions" 23 | runs-on: "ubuntu-latest" 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Check versions match 28 | run: | 29 | if ! (grep -q '\-dev$' VERSION || 30 | [[ "$(head -n 1 CHANGELOG.md)" == "## $(cat VERSION)" ]]); then 31 | echo "VERSION file doesn't match CHANGELOG version." 32 | fi 33 | 34 | tag: 35 | name: "Tag release" 36 | runs-on: "ubuntu-latest" 37 | if: | 38 | github.event_name == 'push' && 39 | github.repository == 'sass/embedded-protocol' && 40 | github.ref == 'refs/heads/main' 41 | 42 | steps: 43 | - uses: actions/checkout@v2 44 | with: 45 | fetch-depth: 2 46 | 47 | - name: Get version information 48 | id: version-info 49 | run: | 50 | echo "::set-output name=VERSION::$(cat VERSION)" 51 | echo "::set-output name=VERSION_MODIFIED::$( 52 | git diff --quiet HEAD^ VERSION && echo false || echo true 53 | )" 54 | - name: Create release 55 | if: | 56 | steps.version-info.outputs.VERSION_MODIFIED == 'true' && 57 | !endsWith(steps.version-info.outputs.VERSION, '-dev') 58 | run: | 59 | git config --global user.name 'SassBot' 60 | git config --global user.email 'sass.bot.beep.boop@gmail.com' 61 | git tag "${{ steps.version-info.outputs.VERSION }}" 62 | git push --tags 63 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.2.0 2 | 3 | * Have the compiler treat several user-generated invalid responses as 4 | compilation errors rather than `ProtocolError`s: 5 | 6 | * Invalid function signatures in `CompileRequest.global_functions`. 7 | 8 | * Non-absolute URLs in `CanonicalizeResponse.result.url`, 9 | `ImportSuccess.source_map_url`, and `FileImportResponse.result.file_url`. 10 | 11 | * Clarify that an invalid signature in a `HostFunction` should treat the current 12 | function as failing, rather than the `HostFunction`. 13 | 14 | ## 1.1.0 15 | 16 | * Add a `charset` option that controls whether or not Sass emits a 17 | `@charset`/BOM for non-ASCII stylesheets. 18 | 19 | ## 1.0.0 20 | 21 | * First stable release. 22 | 23 | ## 1.0.0-beta.18 24 | 25 | * Add a `CompileRequest.source_map_include_sources` field that tells the 26 | compiler to embed the contents of all source files in the generated source 27 | maps. 28 | 29 | ## 1.0.0-beta.17 30 | 31 | * Mark `ImportResponse.result` as optional. Importers should be able to return 32 | `null` to indicate that a file wasn't found. 33 | 34 | ## 1.0.0-beta.16 35 | 36 | * Mark `CompileFailure.span` as mandatory. There's no instance where a 37 | compilation itself should fail without having a source to point to. 38 | 39 | * Make it the compiler's responsibility to verify `HostFunction.signature`. 40 | This ensures that the host doesn't have to parse Sass code. 41 | 42 | ## 1.0.0-beta.15 43 | 44 | * Pluralize `Calculation.arguments`. 45 | 46 | * Explicitly document how hosts should handle calculations. 47 | 48 | ## 1.0.0-beta.14 49 | 50 | * Add support for calculation values. 51 | 52 | ## 1.0.0-beta.13 53 | 54 | * Add the `Value.HwbColor` type. 55 | 56 | * Explicitly specify that compilers may choose which color types to use to 57 | represent each color. 58 | 59 | ## 1.0.0-beta.12 60 | 61 | * Add the `Value.ArgumentList` type, as well as 62 | `FunctionCallResponse.accessed_argument_lists` to track which argument lists 63 | had their keywords accessed. 64 | 65 | ## 1.0.0-beta.11 66 | 67 | * **Breaking change:** We now follow the [protocol buffer style guide]. This means: 68 | * Field names are now all underscore-separated rather than lower camel case. 69 | * Enums are now at the top-level with prefixes rather than surrounded in 70 | enclosing messages. 71 | 72 | * Add `CompileRequest.quiet_deps` and `CompileRequest.verbose` flags to control 73 | how the compiler emits compilation warnings. 74 | 75 | * Add a `CompileSuccess.loaded_urls` field that indicates the URLs that were 76 | loaded by a compilation. 77 | 78 | * Clarify that `CompileRequest.StringInput.url` must be a canonical URL. 79 | 80 | * Fix the documentation of `CanonicalizeRequest` to avoid referring to the 81 | outmoded `CanonicalizeResponse.result.file` field. 82 | 83 | [protocol buffer style guide]: https://developers.google.com/protocol-buffers/docs/style 84 | 85 | ## 1.0.0-beta.10 86 | 87 | * Add `VersionRequest.id` and `VersionResponse.id`. 88 | 89 | ## 1.0.0-beta.9 90 | 91 | * Added `CanonicalizeRequest.fromImport` and `FileImportRequest.fromImport` 92 | fields to allow importers to correctly handle import-only files. 93 | 94 | ## 1.0.0-beta.8 95 | 96 | * Added fields to support requesting and sending formatted errors and logs. 97 | * `CompileRequest.alert_color` 98 | * `CompileRequest.alert_ascii` 99 | * `CompileFailure.formatted` 100 | * `LogEvent.formatted` 101 | 102 | * Remove `OutputStyle.NESTED` and `OutputStyle.COMPACT`. It's unlikely that any 103 | host would support those any time soon. 104 | 105 | ## 1.0.0-beta.7 106 | 107 | * Use `4294967295` as the special ID for error messages that aren't caused by a 108 | specific request, since `-1` isn't representable as a `uint32`. 109 | 110 | ## 1.0.0-beta.6 111 | 112 | * Changed `CompileResponse.id` and `ProtocolError.id` from `int32` to `uint32` 113 | to match the type of all other ID fields. 114 | 115 | * Added protocol versions and created this changelog. 116 | 117 | * Added the `VersionRequest` and `VersionResponse` messages. 118 | 119 | * Delimit messages with varints rather than fixed-size integers. 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This is no longer the repository for the Embedded Sass protocol.** The 2 | protocol definition is now maintained in [the Sass language specification repo]. 3 | 4 | [the Sass language specification repo]: https://github.com/sass/sass/blob/main/spec/embedded-protocol.md 5 | 6 | ## The Embedded Sass Protocol 7 | 8 | * [Overview](#overview) 9 | * [RPCs](#rpcs) 10 | * [Error Handling](#error-handling) 11 | * [Host Language APIs](#host-language-apis) 12 | * [Immutability](#immutability) 13 | * [Indexing](#indexing) 14 | * [Assertions](#assertions) 15 | * [Strings](#strings) 16 | * [Lists](#lists) 17 | * [Maps](#maps) 18 | * [Booleans](#booleans) 19 | * [Null](#null) 20 | * [Calculations](#calculations) 21 | * [Functions](#functions) 22 | * [Versioning](#versioning) 23 | 24 | This repository defines a bidirectional protocol for communicating between a 25 | Sass implementation and a host environment. It allows the host environment to 26 | invoke the Sass compiler on source files, and to define custom functions and 27 | importers in the host language. 28 | 29 | Disclaimer: this is not an official Google product. 30 | 31 | ### Overview 32 | 33 | This protocol operates between two endpoints over a bidirectional stream. One of 34 | these endpoints, the *compiler*, is responsible for compiling Sass stylesheets 35 | to CSS. The other, the *host*, is responsible for telling the compiler what to 36 | compile and for providing implementations of custom importers and functions. 37 | 38 | Messages are sent between the host and the compiler in the form of [protocol 39 | buffers][], using a custom RPC system [defined below][]. The messages and 40 | services that comprise this protocol are defined in [the `.proto` file][] 41 | included in this repository. Most messages are *requests* which require the 42 | other endpoint to produce a *response*, but some are *events* which require no 43 | response. 44 | 45 | [protocol buffers]: https://developers.google.com/protocol-buffers/ 46 | [defined below]: #rpcs 47 | [the `.proto` file]: embedded_sass.proto 48 | 49 | In principle this protocol can work over any bidirectional stream capable of 50 | carrying protocol buffers. However, it's expected that most hosts will invoke 51 | the compiler as a subprocess and communicate using binary protocol buffers over 52 | its standard input and output streams. 53 | 54 | For streams (like standard input and output) that don't have built-in message 55 | boundaries, every message must begin with an unsigned [varint] indicating the 56 | length in bytes of the remaining message. This matches the best practice 57 | described in [the protocol buffer documentation][]. Because JavaScript can't 58 | easily represent integers larger than 2^53 - 1, messages may be no more than 59 | 2^53 - 1 bytes long. Because it's so unlikely that this will come up in 60 | practice, implementations are not required to verify it. 61 | 62 | [varint]: https://developers.google.com/protocol-buffers/docs/encoding#varints 63 | [the protocol buffer documentation]: https://developers.google.com/protocol-buffers/docs/techniques#streaming 64 | 65 | > Note that a number of protocol buffer libraries have built-in utilities for 66 | > reading and writing varint-delimited streams. 67 | 68 | ### RPCs 69 | 70 | All RPCs are wrapped in an outer message that indicates the RPC's type using [a 71 | oneof field][]. There are two wrapper messages: 72 | 73 | [a oneof field]: https://developers.google.com/protocol-buffers/docs/proto3#oneof 74 | 75 | * `InboundMessage` is sent from the host to the compiler. 76 | * `OutboundMessage` is sent from the compiler to the host. 77 | 78 | The host must only send `InboundMessage`s to the compiler, and the compiler must 79 | only send `OutboundMessage`s to the host. 80 | 81 | Each wrapper message contains exactly one RPC. This protocol defines four types 82 | of RPC: 83 | 84 | * *Requests* always include a mandatory `uint32 id` field so that the other 85 | endpoint can respond. All request message types end in `Request`. 86 | * *Responses* include a mandatory `uint32 id` field whose value must be the same 87 | as their associated request's `id`. All response message types begin with the 88 | corresponding request name and end with `Response`. 89 | * *Events* may not be responded to and include no `id` field. All event message 90 | types end with `Event`. 91 | * The `ProtocolError` message, which is sent when one endpoint detects that the 92 | other is doing something invalid. See [Error Handling](#error-handling) below. 93 | 94 | The protocol also defines some messages whose names don't end with `Request`, 95 | `Response`, or `Event`. These are used as structures shared between different 96 | RPCs. 97 | 98 | Implementations must guarantee that they use a unique `id` for every request, 99 | although the same `id` may be used for an inbound request and an outbound 100 | request. They may not use the id `4294967295` (the maximum number representable 101 | by a `uint32`) because it's reserved for [error handling](#error-handling). 102 | 103 | All message-typed fields are documented as either "optional" or "mandatory". If 104 | a field is mandatory, the endpoint that sends that message must guarantee that 105 | it's set to a meaningful value, and the endpoint that receives it must reject 106 | the message if it's not set. 107 | 108 | Some scalar-typed fields may also be documented as "mandatory", which means that 109 | the endpoint that sends the message must guarantee that its value is meaningful. 110 | However, since the default value may be meaningful in some cases, the endpoint 111 | that receives the message is not required to reject it based on mandatory 112 | scalar-typed fields. 113 | 114 | ### Error Handling 115 | 116 | When the compiler detects that the host is violating this protocol, it must send 117 | a `ProtocolError` message to the host. If the error was detected when processing 118 | a request, the `ProtocolError` must have its `id` field set to the request's id. 119 | Otherwise, even if the error was detected while processing a response with an 120 | id, the `id` field must be set to `4294967295` (the maximum number representable 121 | by a `uint32`). 122 | 123 | When the host detects that the compiler is violating this protocol, it does not 124 | need to send a `ProtocolError` message to the compiler. Instead, it should 125 | expose an error to the host's consumers and close the connection with the 126 | compiler. 127 | 128 | An error occurs whenever any requirements set out by this protocol (including 129 | the documentation in `embedded_sass.proto`) are violated. This includes, but is 130 | not limited to: 131 | 132 | * Sending data that can't be parsed as an `InboundMessage` (for the compiler) or 133 | an `OutboundMessage` (for the host). 134 | 135 | * Sending a request with an ID that's in use by another in-flight request. 136 | 137 | * Sending a response with an ID that doesn't correspond to an in-flight 138 | request's ID. 139 | 140 | * Sending a response with an ID that corresponds to the ID of an in-flight 141 | request ID of the incorrect type. 142 | 143 | * Sending a message with a `null` value for a mandatory field. 144 | 145 | The `ProtocolError` message must *not* be used to report Sass language errors. 146 | 147 | ### Host Language API 148 | 149 | Although not strictly part of the protocol, the host language will presumably 150 | provide an API for reading and manipulating SassScript values so that custom 151 | functions can be written in the host language. In order to ensure that custom 152 | functions will behave consistently with built-in Sass functions, the host 153 | language should provide APIs that meet the following guidelines. 154 | 155 | The [Dart `Value` API][] is a good example of an object-oriented API that 156 | follows these guidelines. 157 | 158 | [Dart `Value` API]: https://pub.dartlang.org/documentation/sass/latest/sass/Value-class.html 159 | 160 | #### Immutability 161 | 162 | All SassScript values are immutable, and the API should preserve that fact. No 163 | API calls should be able to modify any SassScript values, including collections 164 | like lists and maps. Instead, API calls should be provided to return new values 165 | with adjusted contents or to copy values into mutable host-language objects. 166 | 167 | If API calls are provided that return a new versions of an object with adjusted 168 | contents, metadata for the returned object (such as the type of list separator 169 | or a number's units) should match that of the original object. 170 | 171 | #### Indexing 172 | 173 | SassScript values use index 1 to refer to the first element and -1 to refer to 174 | the final element. The index 0 is invalid. Furthermore, indexes in Sass strings 175 | refer to [Unicode code points][], not bytes or UTF-16 code units. The API should 176 | provide a means to convert between Sass's indexing scheme and the host 177 | language's indexing scheme, and should encourage authors to treat any indexes 178 | they're passed as Sass-style indexes rather than host-language-style indexes. 179 | 180 | [Unicode code points]: https://en.wikipedia.org/wiki/Code_point 181 | 182 | #### Assertions 183 | 184 | The API should provide an easy means to assert that values are the expected type 185 | and to produce a useful error if they aren't. They should *not* provide a means 186 | to assert that a value is a list, though, since all Sass values should be 187 | treated as lists (see below). 188 | 189 | #### Strings 190 | 191 | API users should be encouraged to return quoted strings unless there's a 192 | particular reason not to. 193 | 194 | Two strings are equal if they have the same text, regardless of whether either 195 | is quoted or not. 196 | 197 | #### Numbers 198 | 199 | The API should provide additional assertions for numbers: 200 | 201 | * that the number doesn't have any units; 202 | * that the number's units are [compatible][] with given expected units; 203 | * that the number is an integer, which for the purposes of Sass numbers means 204 | that its numeric value is within 1e-11 of an integer; 205 | * that the number is in a given range, where being within 1e-11 of the top or 206 | bottom of that range is considered being equal to the top or bottom. 207 | 208 | [compatible]: https://www.w3.org/TR/css-values-4/#compat 209 | 210 | The API should also provide means of converting a number to the equivalent 211 | number with different-but-compatible units, and for returning it as the host 212 | language's integer type if it is an integer. 213 | 214 | Two numbers are equal if they have [compatible][] units, and if their numerical 215 | value (with normalized units) are within 1e-11 of one another. A hash code with 216 | the same equality semantics can be generated for a number `x` by rounding 217 | `x * 1e11` to the nearest integer and taking the hash code of the result. 218 | 219 | #### Colors 220 | 221 | The protocol includes three distinct color value types, `RgbColor`, `HslColor`, 222 | and `HwbColor`. In Sass code and custom functions, colors may be represented or 223 | manipulated in either RGB, HSL, or HWB form, so having multiple types allows 224 | whichever form is currently in use to be sent between endpoints without having 225 | to eagerly normalize it. 226 | 227 | However, users of the host language API should be able to transparently treat 228 | any color object as though it were either RGB, HSL, or HWB form. The API should 229 | provide access to the red, green, and blue, hue, saturation, lightness, 230 | whiteness, and blackness channels of *every* color object. It should use [this 231 | RGB-to-HSL algorithm], [this HSL-to-RGB algorithm], [this RGB-to-HWB algorithm], 232 | and [this HWB-to-RGB algorithm] to convert between representations as necessary. 233 | 234 | [this RGB-to-HSL algorithm]: https://en.wikipedia.org/wiki/HSL_and_HSV#RGB_to_HSL_and_HSV 235 | [this HSL-to-RGB algorithm]: https://www.w3.org/TR/css3-color/#hsl-color 236 | [this RGB-to-HWB algorithm]: https://www.w3.org/TR/css-color-4/#rgb-to-hwb 237 | [this HWB-to-RGB algorithm]: https://www.w3.org/TR/css-color-4/#hwb-to-rgb 238 | 239 | The API should also provide means of changing one or more channels of a color 240 | while leaving other channels as-is. 241 | 242 | Two colors are equal if their RGB forms have the same red, green, blue channels 243 | and alpha channels within 1e-11 of one another. 244 | 245 | #### Lists 246 | 247 | In Sass, every value counts as a list. Maps count as unbracketed comma-separated 248 | lists of two-element unbracketed space-separated key-value lists, and all other 249 | non-list values count as lists that contain that value. The API should make it 250 | easy to treat every value as a list, and should discourage treating values 251 | passed as `Value.List`s specially. 252 | 253 | API users should be encouraged to return unbracketed comma-separated lists 254 | unless there's a particular reason not to. 255 | 256 | Two lists are equal if they have the same elements, separator, and if they're 257 | both bracketed or both unbracketed. An empty list is equal to an empty map. 258 | 259 | `Value.ArgumentList`s should be exposed the same way as any other list, except 260 | that it should also provide access to the keyword map. For object-oriented host 261 | languages, an argument list's class should be a subtype of normal list's. It 262 | should be considered equal to a list with the same elements, regardless of its 263 | keywords. 264 | 265 | #### Maps 266 | 267 | Although maps are transferred as lists of pairs, they should be exposed to the 268 | host language as maps that can be indexed by key, using the notions of equality 269 | described for each type. 270 | 271 | Two maps are equal if they have equal keys that map to equal values, regardless 272 | of the order of the keys in the map. An empty map is equal to an empty list. 273 | 274 | #### Booleans 275 | 276 | The `True` and `False` messages are each singletons representing the Sass values 277 | `true` and `false`, respectively. In Sass, all values other than `false` and 278 | `null` can be used to represent truth, so the API should provide an easy way to 279 | tell if a value is "truthy" (one of those values) or "falsey" (`false` or 280 | `null`). It should encourage users to check this rather than directly testing 281 | for `true` or `false`. 282 | 283 | Two booleans are equal if they're both `true` or both` false`. 284 | 285 | #### Null 286 | 287 | The `Null` message is a singleton representing the Sass `null` value. It should 288 | *not* be represented as the host language's native `null` value, so that it can 289 | expose Sass-specific APIs like the [assertions](#assertions) described above. 290 | 291 | `null` is only equal to `null`. 292 | 293 | #### Calculations 294 | 295 | Calculations are represented similarly to their representation in the Sass 296 | specification, as a tree of binary operations and other calculations that 297 | terminates in numbers or strings. This tree structure may be exposed to the host 298 | language, or the host may choose to keep the structure of calculations opaque. 299 | 300 | Two calculations are equal if their names are equal and each of their arguments 301 | are equal. Two `Calculation.CalculationOperation`s are equal if they have the 302 | same operator and their left and right values are equal, respectively. 303 | 304 | Note that this protocol chooses *not* to require host implementations to 305 | simplify calculations as they're constructed, for the sake of simplicity of 306 | implementation (although hosts *may* do so). This means that a host can 307 | construct calculations like `calc(1 + 1)` which, in Sass, would simplify to 2. 308 | The host is not required to take simplification into account when determining 309 | equality. 310 | 311 | #### Functions 312 | 313 | The protocol allows first-class functions defined in the compiler to be passed 314 | to the host (as `Value.CompilerFunction`s) and vice-versa (as 315 | `Value.HostFunctions)`. It allows the compiler to invoke functions defined in 316 | the host. The host API should hide the distinction between the two function 317 | types as much as possible, but it may refuse to allow host-defined functions to 318 | be invoked on the host, since doing so correctly would require parsing those 319 | functions' signatures. 320 | 321 | Two first-class functions are equal if they have the same ID and they're either 322 | both `CompilerFunction`s or both `HostFunction`s. 323 | 324 | ### Versioning 325 | 326 | This protocol is versioned according to [semver 2.0.0]. The current version is 327 | indicated by the `VERSION` file at the root of the repository. If this file has 328 | a `-dev` prerelease string, that indicates that the currently checked in version 329 | is in development, is not considered a release version, and must not be used by 330 | released versions of compilers or hosts. All release versions will also have 331 | GitHub tags for their version numbers. 332 | 333 | A "breaking change" is defined as per [the protocol buffer rules for updating a 334 | message type]. Compatibility is considered from the perspective of the host. For 335 | example, if a new `InboundMessage` type is added, that's considered a "backwards 336 | compatible" change because older hosts can simply opt not to use it, even though 337 | from the perspective of the compiler a new message type would be a breaking 338 | change. 339 | 340 | [the protocol buffer rules for updating a message type]: https://developers.google.com/protocol-buffers/docs/proto#updating 341 | 342 | Hosts are generally expected to be responsible for installing appropriate 343 | compiler versions as part of their installation process, which should limit the 344 | potential for incompatible versions between the two. For this reason, version 345 | numbers are intended to be primarily an advisory for humans as to the degree of 346 | change over time. 347 | 348 | In some cases, the version number will be marked as "pending". This indicates 349 | that the next version of the protocol is still under active development, and may 350 | be waiting for additional pull requests before it's finalized. Hosts and 351 | compilers should never cut releases that target pending protocol versions. 352 | 353 | [semver 2.0.0]: https://semver.org/spec/v2.0.0.html 354 | -------------------------------------------------------------------------------- /embedded_sass.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google Inc. Use of this source code is governed by an 2 | // MIT-style license that can be found in the LICENSE file or at 3 | // https://opensource.org/licenses/MIT. 4 | 5 | syntax = "proto3"; 6 | 7 | package sass.embedded_protocol; 8 | 9 | // The wrapper type for all messages sent from the host to the compiler. This 10 | // provides a `oneof` that makes it possible to determine the type of each 11 | // inbound message. 12 | message InboundMessage { 13 | // A request for information about the version of the embedded compiler. The 14 | // host can use this to provide diagnostic information to the user, to check 15 | // which features the compiler supports, or to ensure that it's compatible 16 | // with the same protocol version the compiler supports. 17 | message VersionRequest { 18 | // This version request's id. Mandatory. 19 | uint32 id = 1; 20 | 21 | // This message's contents are intentionally empty. It just acts as a signal 22 | // to the compiler to send a VersionResponse. More fields may be added in 23 | // the future. 24 | } 25 | 26 | // A request that compiles an entrypoint to CSS. 27 | message CompileRequest { 28 | // This compilation's request id. This is included in messages sent from the 29 | // compiler to the host. Mandatory. 30 | uint32 id = 1; 31 | 32 | // An input stylesheet provided as plain text, rather than loaded from the 33 | // filesystem. 34 | message StringInput { 35 | // The contents of the stylesheet. 36 | string source = 1; 37 | 38 | // The location from which `source` was loaded. If this is empty, it 39 | // indicates that the URL is unknown. 40 | // 41 | // This must be a canonical URL recognized by `importer`, if it's passed. 42 | string url = 2; 43 | 44 | // The syntax to use to parse `source`. 45 | Syntax syntax = 3; 46 | 47 | // The importer to use to resolve imports relative to `url`. 48 | Importer importer = 4; 49 | } 50 | 51 | // The input stylesheet to parse. Mandatory. 52 | oneof input { 53 | // A stylesheet loaded from its contents. 54 | StringInput string = 2; 55 | 56 | // A stylesheet loaded from the given path on the filesystem. 57 | string path = 3; 58 | } 59 | 60 | // How to format the CSS output. 61 | OutputStyle style = 4; 62 | 63 | // Whether to generate a source map. Note that this will *not* add a source 64 | // map comment to the stylesheet; that's up to the host or its users. 65 | bool source_map = 5; 66 | 67 | // A wrapper message that represents either a user-defined importer or a 68 | // load path on disk. This must be a wrapper because `oneof` types can't be 69 | // `repeated`. 70 | message Importer { 71 | // The possible types of importer. Mandatory. 72 | oneof importer { 73 | // A built-in importer that loads Sass files within the given directory 74 | // on disk. 75 | string path = 1; 76 | 77 | // A unique ID for a user-defined importer. This ID will be included in 78 | // outbound `CanonicalizeRequest` and `ImportRequest` messages to 79 | // indicate which importer is being called. The host is responsible for 80 | // generating this ID and ensuring that it's unique across all 81 | // importers registered for this compilation. 82 | uint32 importer_id = 2; 83 | 84 | // A unique ID for a special kind of user-defined importer that tells 85 | // the compiler where to look for files on the physical filesystem, but 86 | // leaves the details of resolving partials and extensions and loading 87 | // the file from disk up to the compiler itself. 88 | // 89 | // This ID will be included in outbound `FileImportRequest` messages to 90 | // indicate which importer is being called. The host is responsible for 91 | // generating this ID and ensuring that it's unique across all importers 92 | // registered for this compilation. 93 | uint32 file_importer_id = 3; 94 | } 95 | } 96 | 97 | // Importers (including load paths on the filesystem) to use when resolving 98 | // imports that can't be resolved relative to the file that contains it. Each 99 | // importer is checked in order until one recognizes the imported URL. 100 | repeated Importer importers = 6; 101 | 102 | // Signatures for custom global functions whose behavior is defined by the 103 | // host. 104 | // 105 | // If this is not a valid Sass function signature that could appear after 106 | // `@function` in a Sass stylesheet (such as `mix($color1, $color2, $weight: 107 | // 50%)`), or if it conflicts with a function name that's built into the 108 | // Sass language, the compiler must treat the compilation as failed. 109 | // 110 | // Compilers must ensure that pure-Sass functions take precedence over 111 | // custom global functions. 112 | repeated string global_functions = 7; 113 | 114 | // Whether to use terminal colors in the formatted message of errors and 115 | // logs. 116 | bool alert_color = 8; 117 | 118 | // Whether to encode the formatted message of errors and logs in ASCII. 119 | bool alert_ascii = 9; 120 | 121 | // Whether to report all deprecation warnings or only the first few ones. 122 | // If this is `false`, the compiler may choose not to send events for 123 | // repeated deprecation warnings. If this is `true`, the compiler must emit 124 | // an event for every deprecation warning it encounters. 125 | bool verbose = 10; 126 | 127 | // Whether to omit events for deprecation warnings coming from dependencies 128 | // (files loaded from a different importer than the input). 129 | bool quiet_deps = 11; 130 | 131 | // Whether to include sources in the generated sourcemap 132 | bool source_map_include_sources = 12; 133 | 134 | // Whether to emit a `@charset`/BOM for non-ASCII stylesheets. 135 | bool charset = 13; 136 | } 137 | 138 | // A response indicating the result of canonicalizing an imported URL. 139 | message CanonicalizeResponse { 140 | uint32 id = 1; 141 | 142 | // The result of canonicalization. Optional. If this is `null`, it indicates 143 | // that the importer either did not recognize the URL, or could not find a 144 | // stylesheet at the location it referred to. 145 | oneof result { 146 | // The successfully canonicalized URL. 147 | // 148 | // If this is not an absolute URL (including scheme), the compiler must 149 | // treat that as an error thrown by the importer. 150 | string url = 2; 151 | 152 | // An error message explaining why canonicalization failed. 153 | // 154 | // This indicates that a stylesheet was found, but a canonical URL for it 155 | // could not be determined. If no stylesheet was found, `result` should be 156 | // `null` instead. 157 | string error = 3; 158 | } 159 | } 160 | 161 | // A response indicating the result of importing a canonical URL. 162 | message ImportResponse { 163 | uint32 id = 1; 164 | 165 | // The stylesheet's contents were loaded successfully. 166 | message ImportSuccess { 167 | // The text of the stylesheet. Mandatory. 168 | string contents = 1; 169 | 170 | // The syntax of `contents`. Mandatory. 171 | Syntax syntax = 2; 172 | 173 | // An absolute, browser-accessible URL indicating the resolved location of 174 | // the imported stylesheet. Optional. 175 | // 176 | // This should be a `file:` URL if one is available, but an `http:` URL is 177 | // acceptable as well. If no URL is supplied, a `data:` URL is generated 178 | // automatically from `contents`. 179 | // 180 | // If this is provided and is not an absolute URL (including scheme) the 181 | // compiler must treat that as an error thrown by the importer. 182 | string source_map_url = 3; 183 | } 184 | 185 | // The result of loading the URL. Optional. If this is `null`, it indicates 186 | // that the importer either did not recognize the URL, or could not find a 187 | // stylesheet at the location it referred to. 188 | oneof result { 189 | // The contents of the loaded stylesheet. 190 | ImportSuccess success = 2; 191 | 192 | // An error message explaining why the URL could not be loaded. 193 | string error = 3; 194 | } 195 | } 196 | 197 | // A response indicating the result of redirecting a URL to the filesystem. 198 | message FileImportResponse { 199 | uint32 id = 1; 200 | 201 | // The result of loading the URL. Optional. A null result indicates that the 202 | // importer did not recognize the URL and other importers or load paths 203 | // should be tried. 204 | oneof result { 205 | // The absolute `file:` URL to look for the file on the physical 206 | // filesystem. 207 | // 208 | // The compiler must verify to the best of its ability that this URL 209 | // follows the format for an absolute `file:` URL on the current operating 210 | // system without a hostname. If it doesn't, the compiler must treat that 211 | // as an error thrown by the importer. See 212 | // https://en.wikipedia.org/wiki/File_URI_scheme for details on the 213 | // format. 214 | // 215 | // The compiler must handle turning this into a canonical URL by resolving 216 | // it for partials, file extensions, and index files. The compiler must 217 | // then loading the contents of the resulting canonical URL from the 218 | // filesystem. 219 | string file_url = 2; 220 | 221 | // An error message explaining why the URL could not be loaded. 222 | string error = 3; 223 | } 224 | } 225 | 226 | // A response indicating the result of calling a custom Sass function defined 227 | // in the host. 228 | message FunctionCallResponse { 229 | uint32 id = 1; 230 | 231 | // The result of calling the function. Mandatory. 232 | oneof result { 233 | // The return value of a successful function call. 234 | Value success = 2; 235 | 236 | // An error message explaining why the function call failed. 237 | string error = 3; 238 | } 239 | 240 | // The IDs of all `Value.ArgumentList`s in `FunctionCallRequest.arguments` 241 | // whose keywords were accessed. See `Value.ArgumentList` for details. 242 | // Mandatory if `result.success` is set. This may not include the special 243 | // value `0` and it may not include multiple instances of the same ID. 244 | repeated uint32 accessed_argument_lists = 4; 245 | } 246 | 247 | // The wrapped message. Mandatory. 248 | oneof message { 249 | CompileRequest compile_request = 2; 250 | CanonicalizeResponse canonicalize_response = 3; 251 | ImportResponse import_response = 4; 252 | FileImportResponse file_import_response = 5; 253 | FunctionCallResponse function_call_response = 6; 254 | VersionRequest version_request = 7; 255 | } 256 | } 257 | 258 | // The wrapper type for all messages sent from the compiler to the host. This 259 | // provides a `oneof` that makes it possible to determine the type of each 260 | // outbound message. 261 | message OutboundMessage { 262 | // A response that contains the version of the embedded compiler. 263 | message VersionResponse { 264 | // This version request's id. Mandatory. 265 | uint32 id = 5; 266 | 267 | // The version of the embedded protocol, in semver format. 268 | string protocol_version = 1; 269 | 270 | // The version of the embedded compiler package. This has no guaranteed 271 | // format, although compilers are encouraged to use semver. 272 | string compiler_version = 2; 273 | 274 | // The version of the Sass implementation that the embedded compiler wraps. 275 | // This has no guaranteed format, although Sass implementations are 276 | // encouraged to use semver. 277 | string implementation_version = 3; 278 | 279 | // The name of the Sass implementation that the embedded compiler wraps. 280 | string implementation_name = 4; 281 | } 282 | 283 | // A response that contains the result of a compilation. 284 | message CompileResponse { 285 | // The compilation's request id. Mandatory. 286 | uint32 id = 1; 287 | 288 | // A message indicating that the Sass file was successfully compiled to CSS. 289 | message CompileSuccess { 290 | // The compiled CSS. 291 | string css = 1; 292 | 293 | // The JSON-encoded source map, or the empty string if 294 | // `CompileRequest.source_map` was `false`. 295 | // 296 | // The compiler must not add a `"file"` key to this source map. It's the 297 | // host's (or the host's user's) responsibility to determine how the 298 | // generated CSS can be reached from the source map. 299 | string source_map = 2; 300 | 301 | // The canonical URLs of all source files loaded during the compilation. 302 | // 303 | // The compiler must ensure that each canonical URL appears only once in 304 | // this list. This must include the entrypoint file's URL if either 305 | // `CompileRequest.input.path` or `CompileRequest.StringInput.url` was 306 | // passed. 307 | repeated string loaded_urls = 3; 308 | } 309 | 310 | // A message indicating that the Sass file could not be successfully 311 | // compiled to CSS. 312 | message CompileFailure { 313 | // A message describing the reason for the failure. 314 | string message = 1; 315 | 316 | // The span associated with the failure. Mandatory. 317 | SourceSpan span = 2; 318 | 319 | // The stack trace associated with the failure. 320 | // 321 | // The empty string indicates that no stack trace is available. Otherwise, 322 | // the format of this stack trace is not specified and is likely to be 323 | // inconsistent between implementations. 324 | string stack_trace = 3; 325 | 326 | // A formatted, human-readable string that contains the message, span 327 | // (if available), and trace (if available). The format of this string is 328 | // not specified and is likely to be inconsistent between implementations. 329 | string formatted = 4; 330 | } 331 | 332 | // The success or failure result of the compilation. Mandatory. 333 | oneof result { 334 | // The result of a successful compilation. 335 | CompileSuccess success = 2; 336 | 337 | // The result of a failed compilation. 338 | CompileFailure failure = 3; 339 | } 340 | } 341 | 342 | // An event indicating that a message should be displayed to the user. 343 | message LogEvent { 344 | // The request id for the compilation that triggered the message. Mandatory. 345 | uint32 compilation_id = 1; 346 | 347 | LogEventType type = 2; 348 | 349 | // The text of the message. 350 | string message = 3; 351 | 352 | // The span associated with this message. Optional. 353 | SourceSpan span = 4; 354 | 355 | // The stack trace associated with this message. 356 | // 357 | // The empty string indicates that no stack trace is available. Otherwise, 358 | // the format of this stack trace is not specified and is likely to be 359 | // inconsistent between implementations. 360 | string stack_trace = 5; 361 | 362 | // A formatted, human-readable string that contains the message, span (if 363 | // available), and trace (if available). The format of this string is not 364 | // specified and is likely to be inconsistent between implementations. 365 | string formatted = 6; 366 | } 367 | 368 | // A request for a custom importer to convert an imported URL to its canonical 369 | // format. 370 | // 371 | // If the URL is not recognized by this importer, or if no stylesheet is found 372 | // at that URL, `CanonicalizeResponse.result` must be `null`. Otherwise, the 373 | // importer must return an absolute URL, including a scheme. 374 | // 375 | // > The host's documentation should encourage the use of file importers (via 376 | // > `CompileRequest.Importer.file_importer_id`, `FileImportRequest`, and 377 | // > `FileImportResponse`) for any importers that simply refer to files on 378 | // > disk. This will allow Sass to handle the logic of resolving partials, 379 | // > file extensions, and index files. 380 | // 381 | // If Sass has already loaded a stylesheet with the returned canonical URL, it 382 | // re-uses the existing parse tree. This means that importers must ensure that 383 | // the same canonical URL always refers to the same stylesheet, *even across 384 | // different importers*. Importers must also ensure that any canonicalized 385 | // URLs they return can be passed back to `CanonicalizeRequest` and will be 386 | // returned unchanged. 387 | // 388 | // If this importer's URL format supports file extensions, it should 389 | // canonicalize them the same way as the default filesystem importer: 390 | // 391 | // * The importer should look for stylesheets by adding the prefix `_` to the 392 | // URL's basename, and by adding the extensions `.sass` and `.scss` if the 393 | // URL doesn't already have one of those extensions. For example, if the URL 394 | // was `foo/bar/baz`, the importer would look for: 395 | // 396 | // * `foo/bar/baz.sass` 397 | // * `foo/bar/baz.scss` 398 | // * `foo/bar/_baz.sass` 399 | // * `foo/bar/_baz.scss` 400 | // 401 | // If the URL was foo/bar/baz.scss, the importer would just look for: 402 | // 403 | // * `foo/bar/baz.scss` 404 | // * `foo/bar/_baz.scss` 405 | // 406 | // If the importer finds a stylesheet at more than one of these URLs, it 407 | // should respond with a `CanonicalizeResponse.result.error` indicating that 408 | // the import is ambiguous. Note that if the extension is explicitly 409 | // specified, a stylesheet with another extension may exist without error. 410 | // 411 | // * If none of the possible paths is valid, the importer should perform the 412 | // same resolution on the URL followed by `/index`. In the example above, it 413 | // would look for: 414 | // 415 | // * `foo/bar/baz/_index.sass` 416 | // * `foo/bar/baz/index.sass` 417 | // * `foo/bar/baz/_index.scss` 418 | // * `foo/bar/baz/index.scss` 419 | // 420 | // As above, if the importer finds a stylesheet at more than one of these 421 | // URLs, it should respond with a `CanonicalizeResponse.result.error` 422 | // indicating that the import is ambiguous. 423 | message CanonicalizeRequest { 424 | uint32 id = 1; 425 | 426 | // The request id for the compilation that triggered the message. Mandatory. 427 | uint32 compilation_id = 2; 428 | 429 | // The unique ID of the importer being invoked. This must match an importer 430 | // ID passed to this compilation in `CompileRequest.importers` or 431 | // `CompileRequest.input.string.importer`. Mandatory. 432 | uint32 importer_id = 3; 433 | 434 | // The URL of the import to be canonicalized. This may be either absolute or 435 | // relative. 436 | // 437 | // When loading a URL, the compiler must first try resolving that URL 438 | // relative to the canonical URL of the current file, and canonicalizing the 439 | // result using the importer that loaded the current file. If this returns 440 | // `null`, the compiler must then try canonicalizing the original URL with 441 | // each importer in order until one returns something other than `null`. 442 | // That is the result of the import. 443 | string url = 4; 444 | 445 | /// Whether this request comes from an `@import` rule. 446 | /// 447 | /// When evaluating `@import` rules, URLs should canonicalize to an 448 | /// [import-only file] if one exists for the URL being canonicalized. 449 | /// Otherwise, canonicalization should be identical for `@import` and `@use` 450 | /// rules. 451 | /// 452 | /// [import-only file]: https://sass-lang.com/documentation/at-rules/import#import-only-files 453 | bool from_import = 5; 454 | } 455 | 456 | // A request for a custom importer to load the contents of a stylesheet. 457 | message ImportRequest { 458 | uint32 id = 1; 459 | 460 | // The request id for the compilation that triggered the message. Mandatory. 461 | uint32 compilation_id = 2; 462 | 463 | // The unique ID of the importer being invoked. This must match an 464 | // `Importer.importer_id` passed to this compilation in 465 | // `CompileRequest.importers` or `CompileRequest.input.string.importer`. 466 | // Mandatory. 467 | uint32 importer_id = 3; 468 | 469 | // The canonical URL of the import. This is guaranteed to be a URL returned 470 | // by a `CanonicalizeRequest` to this importer. 471 | string url = 4; 472 | } 473 | 474 | // A request for a custom filesystem importer to load the contents of a 475 | // stylesheet. 476 | // 477 | // A filesystem importer is represented in the compiler as an [importer]. When 478 | // the importer is invoked with a string `string`: 479 | // 480 | // [importer]: https://github.com/sass/sass/tree/main/spec/modules.md#importer 481 | // 482 | // * If `string` is an absolute URL whose scheme is `file`: 483 | // 484 | // * Let `url` be string. 485 | // 486 | // * Otherwise: 487 | // 488 | // * Let `fromImport` be `true` if the importer is being run for an 489 | // `@import` and `false` otherwise. 490 | // 491 | // * Let `response` be the result of sending a `FileImportRequest` with 492 | // `string` as its `url` and `fromImport` as `from_import`. 493 | // 494 | // * If `response.result` is null, return null. 495 | // 496 | // * Otherwise, if `response.result.error` is set, throw an error. 497 | // 498 | // * Otherwise, let `url` be `response.result.file_url`. 499 | // 500 | // * Let `resolved` be the result of [resolving `url`]. 501 | // 502 | // * If `resolved` is null, return null. 503 | // 504 | // * Let `text` be the contents of the file at `resolved`. 505 | // 506 | // * Let `syntax` be: 507 | // * "scss" if `url` ends in `.scss`. 508 | // * "indented" if `url` ends in `.sass`. 509 | // * "css" if `url` ends in `.css`. 510 | // 511 | // > The algorithm for resolving a `file:` URL guarantees that `url` will have 512 | // > one of these extensions. 513 | // 514 | // * Return `text`, `syntax`, and `resolved`. 515 | // 516 | // [resolving `url`]: https://github.com/sass/sass/tree/main/spec/modules.md#resolving-a-file-url 517 | message FileImportRequest { 518 | uint32 id = 1; 519 | 520 | // The request id for the compilation that triggered the message. Mandatory. 521 | uint32 compilation_id = 2; 522 | 523 | // The unique ID of the importer being invoked. This must match an 524 | // `Importer.file_importer_id` passed to this compilation in 525 | // `CompileRequest.importers` or `CompileRequest.input.string.importer`. 526 | // Mandatory. 527 | uint32 importer_id = 3; 528 | 529 | // The (non-canonicalized) URL of the import. 530 | string url = 4; 531 | 532 | /// Whether this request comes from an `@import` rule. 533 | /// 534 | /// When evaluating `@import` rules, filesystem importers should load an 535 | /// [import-only file] if one exists for the URL being canonicalized. 536 | /// Otherwise, canonicalization should be identical for `@import` and `@use` 537 | /// rules. 538 | /// 539 | /// [import-only file]: https://sass-lang.com/documentation/at-rules/import#import-only-files 540 | bool from_import = 5; 541 | } 542 | 543 | // A request to invoke a custom Sass function and return its result. 544 | message FunctionCallRequest { 545 | uint32 id = 1; 546 | 547 | // The request id for the compilation that triggered the message. Mandatory. 548 | uint32 compilation_id = 2; 549 | 550 | // An identifier that indicates which function to invoke. Mandatory. 551 | oneof identifier { 552 | // The name of the function to invoke. 553 | // 554 | // This must match the name of a function signature the host passed to the 555 | // corresponding `CompileRequest.global_functions` call, including hyphens 556 | // and underscores. 557 | string name = 3; 558 | 559 | // The opaque ID of the function to invoke. 560 | // 561 | // This must match the ID of a `Value.HostFunction` that the host passed 562 | // to the compiler. 563 | uint32 function_id = 4; 564 | } 565 | 566 | // The arguments passed to the function, in the order they appear in the 567 | // function signature passed to `CompileRequest.global_functions`. Mandatory. 568 | // 569 | // The compiler must ensure that a valid number of arguments are passed for 570 | // the given signature, that default argument values are instantiated 571 | // appropriately, and that variable argument lists (`$args...`) are passed 572 | // as `Value.ArgumentList`s. 573 | repeated Value arguments = 5; 574 | } 575 | 576 | // The wrapped message. Mandatory. 577 | oneof message { 578 | ProtocolError error = 1; 579 | CompileResponse compile_response = 2; 580 | LogEvent log_event = 3; 581 | CanonicalizeRequest canonicalize_request = 4; 582 | ImportRequest import_request = 5; 583 | FileImportRequest file_import_request = 6; 584 | FunctionCallRequest function_call_request = 7; 585 | VersionResponse version_response = 8; 586 | } 587 | } 588 | 589 | // Possible ways to format the CSS output. The compiler is not required to 590 | // support all possible options; if the host requests an unsupported style, the 591 | // compiler should choose the closest supported style. 592 | enum OutputStyle { 593 | // Each selector and declaration is written on its own line. 594 | EXPANDED = 0; 595 | 596 | // The entire stylesheet is written on a single line, with as few characters 597 | // as possible. 598 | COMPRESSED = 1; 599 | } 600 | 601 | // Possible syntaxes for a Sass stylesheet. 602 | enum Syntax { 603 | // The CSS-superset `.scss` syntax. 604 | SCSS = 0; 605 | 606 | // The indented `.sass` syntax. 607 | INDENTED = 1; 608 | 609 | // Plain CSS syntax that doesn't support any special Sass features. 610 | CSS = 2; 611 | } 612 | 613 | // The possible types of [LogEvent]. 614 | enum LogEventType { 615 | // A warning for something other than a deprecated Sass feature. Often emitted 616 | // due to a stylesheet using the `@warn` rule. 617 | WARNING = 0; 618 | 619 | // A warning indicating that the stylesheet is using a deprecated Sass 620 | // feature. Compilers should not add text like "deprecation warning" to 621 | // deprecation warnings; it's up to the host to determine how to signal that 622 | // to the user. 623 | DEPRECATION_WARNING = 1; 624 | 625 | // A message generated by the user for their own debugging purposes. 626 | DEBUG = 2; 627 | } 628 | 629 | // An error reported when an endpoint violates the embedded Sass protocol. 630 | message ProtocolError { 631 | ProtocolErrorType type = 1; 632 | 633 | // The ID of the request that had an error. This MUST be `4294967295` if the 634 | // request ID couldn't be determined, or if the error is being reported for a 635 | // response or an event. 636 | uint32 id = 2; 637 | 638 | // A human-readable message providing more detail about the error. 639 | string message = 3; 640 | } 641 | 642 | // Potential types of protocol errors. 643 | enum ProtocolErrorType { 644 | // A message was received that couldn't be decoded as an `InboundMessage` (for 645 | // the compiler) or `OutboundMessage` (for the host). 646 | PARSE = 0; 647 | 648 | // A message was received that violated a documented restriction, such as not 649 | // providing a mandatory field. 650 | PARAMS = 1; 651 | 652 | // Something unexpected went wrong within the endpoint. 653 | INTERNAL = 2; 654 | } 655 | 656 | // A chunk of a source file. 657 | message SourceSpan { 658 | // The text covered by the source span. Compilers must guarantee that this is 659 | // the text between `start.offset` and `end.offset` in the source file 660 | // referred to by `url`. 661 | string text = 1; 662 | 663 | // A single point in a source file. 664 | message SourceLocation { 665 | // The 0-based offset of this location within the source file. Mandatory. 666 | uint32 offset = 1; 667 | 668 | // The 0-based line number of this location within the source file. 669 | // Mandatory. 670 | uint32 line = 2; 671 | 672 | // The 0-based column number of this location within its line. Mandatory. 673 | uint32 column = 3; 674 | } 675 | 676 | // The location of the first character in this span. Mandatory. 677 | SourceLocation start = 2; 678 | 679 | // The location of the first character after this span. Optional. 680 | // 681 | // If this is omitted, it indicates that the span is empty and points 682 | // immediately before `start`. In that case, `text` must be empty. 683 | // 684 | // This must not point to a location before `start`. 685 | SourceLocation end = 3; 686 | 687 | // The URL of the file to which this span refers. 688 | // 689 | // This may be empty, indicating that the span refers to a 690 | // `CompileRequest.StringInput` file that doesn't specify a URL. 691 | string url = 4; 692 | 693 | // Additional source text surrounding this span. 694 | // 695 | // If this isn't empty, it must contain `text`. Furthermore, `text` must begin 696 | // at column `start.column` of a line in `context`. 697 | // 698 | // This usually contains the full lines the span begins and ends on if the 699 | // span itself doesn't cover the full lines. 700 | string context = 5; 701 | } 702 | 703 | // A SassScript value, passed to and returned by functions. 704 | message Value { 705 | // A SassScript string value. 706 | message String { 707 | // The contents of the string. Mandatory. 708 | string text = 1; 709 | 710 | // Whether the string is quoted or unquoted. Mandatory. 711 | bool quoted = 2; 712 | } 713 | 714 | // A SassScript number value. 715 | message Number { 716 | // The number's numeric value. Mandatory. 717 | double value = 1; 718 | 719 | // The number's numerator units. 720 | // 721 | // The endpoint sending the number must ensure that no numerator units are 722 | // [compatible][] with any denominator units. Such compatible units must be 723 | // simplified away according to the multiplicative factor between them 724 | // defined in the CSS Values and Units spec. 725 | // 726 | // [compatible]: https://www.w3.org/TR/css-values-4/#compat 727 | repeated string numerators = 2; 728 | 729 | // The number's denominator units. 730 | repeated string denominators = 3; 731 | } 732 | 733 | // A SassScript color value, represented as red, green, and blue channels. 734 | // 735 | // All Sass color values can be equivalently represented as `RgbColor`, 736 | // `HslColor`, and `HwbColor` messages without loss of color information that 737 | // can affect CSS rendering. As such, either endpoint may choose to send any 738 | // color value as any one of these three messages. 739 | message RgbColor { 740 | // The color's red channel. Mandatory. May not be above 255. 741 | uint32 red = 1; 742 | 743 | // The color's green channel. Mandatory. May not be above 255. 744 | uint32 green = 2; 745 | 746 | // The color's blue channel. Mandatory. May not be above 255. 747 | uint32 blue = 3; 748 | 749 | // The color's alpha channel. Mandatory. Must be between 0 and 1, 750 | // inclusive. 751 | double alpha = 4; 752 | } 753 | 754 | // A SassScript color value, represented as hue, saturation, and lightness channels. 755 | message HslColor { 756 | // The color's hue. Mandatory. 757 | double hue = 1; 758 | 759 | // The color's percent saturation. Mandatory. Must be between 0 and 100, 760 | // inclusive. 761 | double saturation = 2; 762 | 763 | // The color's percent lightness. Mandatory. Must be between 0 and 100, 764 | // inclusive. 765 | double lightness = 3; 766 | 767 | // The color's alpha channel. Mandatory. Must be between 0 and 1, 768 | // inclusive. 769 | double alpha = 4; 770 | } 771 | 772 | // A SassScript color value, represented as hue, whiteness, and blackness 773 | // channels. 774 | message HwbColor { 775 | // The color's hue. Mandatory. 776 | double hue = 1; 777 | 778 | // The color's percent whiteness. Mandatory. Must be between 0 and 100, 779 | // inclusive. The sum of `whiteness` and `blackness` must not exceed 100. 780 | double whiteness = 2; 781 | 782 | // The color's percent blackness. Mandatory. Must be between 0 and 100, 783 | // inclusive. The sum of `whiteness` and `blackness` must not exceed 100. 784 | double blackness = 3; 785 | 786 | // The color's alpha channel. Mandatory. Must be between 0 and 1, 787 | // inclusive. 788 | double alpha = 4; 789 | } 790 | 791 | // A SassScript list value. 792 | message List { 793 | // The type of separator for this list. Mandatory. 794 | ListSeparator separator = 1; 795 | 796 | // Whether this list has square brackets. Mandatory. 797 | bool has_brackets = 2; 798 | 799 | // The elements of this list. 800 | repeated Value contents = 3; 801 | } 802 | 803 | // A SassScript map value. 804 | message Map { 805 | // A single key/value pair in the map. 806 | message Entry { 807 | // The key this entry is associated with. Mandatory. 808 | Value key = 1; 809 | 810 | // The value associated with this key. Mandatory. 811 | Value value = 2; 812 | } 813 | 814 | // The entries in this map. The sending endpoint must guarantee that no two 815 | // entries have the same key. 816 | repeated Entry entries = 1; 817 | } 818 | 819 | // A first-class function defined in the compiler. New `CompilerFunction`s may 820 | // only be created by the compiler, but the host may pass `CompilerFunction`s 821 | // back to the compiler as long as their IDs match IDs of functions received 822 | // by the host during that same compilation. 823 | message CompilerFunction { 824 | // A unique ID for this function. The compiler is responsible for generating 825 | // this ID and ensuring it's unique across all functions passed to the host 826 | // for this compilation. Mandatory. 827 | uint32 id = 1; 828 | } 829 | 830 | // An anonymous custom function defined in the host. New `HostFunction`s may 831 | // only be created by the host, and `HostFunction`s may *never* be passed from 832 | // the compiler to the host. The compiler must instead pass a 833 | // `CompilerFunction` that wraps the `HostFunction`. 834 | message HostFunction { 835 | // A unique ID for this function. The compiler must pass this ID as 836 | // `OutboundRequest.FunctionCallRequest.id` when invoking this function. The 837 | // host is responsible for generating this ID and ensuring it's unique 838 | // across all functions for *all* compilations. Mandatory. 839 | uint32 id = 1; 840 | 841 | // The signature for this function. Mandatory. 842 | // 843 | // If this isn't a valid Sass function signature that could appear after 844 | // `@function` in a Sass stylesheet (such as `mix($color1, $color2, $weight: 845 | // 50%)`), the compiler must treat it as though the function that returned 846 | // this `HostFunction` threw an error. 847 | // 848 | // > This ensures that the host doesn't need to be able to correctly parse 849 | // > the entire function declaration syntax. 850 | // 851 | // The compiler may not invoke the function by its name, since it's not 852 | // guaranteed to be globally unique. However, it may use the name to 853 | // generate the string representation of this function. 854 | string signature = 2; 855 | } 856 | 857 | // A SassScript argument list value. This represents rest arguments passed to 858 | // a function's `$arg...` parameter. Unlike a normal `List`, an argument list 859 | // has an associated keywords map which tracks keyword arguments passed in 860 | // alongside positional arguments. 861 | // 862 | // For each `ArgumentList` in `FunctionCallRequest.arguments` (including those 863 | // nested within `List`s and `Map`s), the host must track whether its keyword 864 | // arguments were accessed by the user. If they were, it must add its 865 | // `ArgumentList.id` to `FunctionCallResponse.accessed_argument_lists`. 866 | // 867 | // The compiler must treat every `ArgumentList` whose `ArgumentList.id` 868 | // appears in `FunctionCallResponse.accessed_argument_lists` as though it had 869 | // been passed to `meta.keywords()`. 870 | message ArgumentList { 871 | // An ID for this argument list that's unique within the scope of a given 872 | // `FunctionCallRequest`. 873 | // 874 | // The special ID `0` is reserved for `ArgumentList`s created by the host, 875 | // and may not be used by the compiler. These `ArgumentList`s do not need to 876 | // have their IDs added to `FunctionCallResponse.accessed_argument_lists`, 877 | // and the compiler should treat them as though their keywords have always 878 | // been accessed. 879 | uint32 id = 1; 880 | 881 | // The type of separator for this list. The compiler must set this, but 882 | // the host may omit it for `ArgumentList`s that were originally created by 883 | // the compiler (that is, those with a non-0 ID). 884 | ListSeparator separator = 2; 885 | 886 | // The argument list's positional contents. The compiler must set this, but 887 | // the host may omit it for `ArgumentList`s that were originally created by 888 | // the compiler (that is, those with a non-0 ID). 889 | repeated Value contents = 3; 890 | 891 | // The argument list's keywords. The compiler must set this, but the host 892 | // may omit it for `ArgumentList`s that were originally created by the 893 | // compiler (that is, those with a non-0 ID). 894 | map keywords = 4; 895 | } 896 | 897 | // A SassScript calculation value. The compiler must send fully [simplified] 898 | // calculations, meaning that simplifying it again will produce the same 899 | // calculation. The host is not required to simplify calculations. 900 | // 901 | // [simplified]: https://github.com/sass/sass/tree/main/spec/types/calculation.md#simplifying-a-calculation 902 | // 903 | // The compiler must simplify any calculations it receives from the host 904 | // before returning them from a function. If this simplification produces an 905 | // error, it should be treated as though the function call threw that error. 906 | // It should *not* be treated as a protocol error. 907 | message Calculation { 908 | // The calculation's name. Mandatory. The host may only set this to names 909 | // that the Sass specification uses to create calculations. 910 | string name = 1; 911 | 912 | // The calculation's arguments. Mandatory. The host must use exactly the 913 | // number of arguments used by the Sass specification for calculations with 914 | // the given `name`. 915 | repeated CalculationValue arguments = 2; 916 | 917 | // A single component of a calculation expression. 918 | message CalculationValue { 919 | // The value of the component. Mandatory. 920 | oneof value { 921 | Number number = 1; 922 | 923 | // An unquoted string, as from a function like `var()` or `env()`. 924 | string string = 2; 925 | 926 | // An unquoted string as created by interpolation for 927 | // backwards-compatibility with older Sass syntax. 928 | string interpolation = 3; 929 | 930 | CalculationOperation operation = 4; 931 | Calculation calculation = 5; 932 | } 933 | } 934 | 935 | // A binary operation that appears in a calculation. 936 | message CalculationOperation { 937 | // The operator to perform. 938 | CalculationOperator operator = 1; 939 | 940 | // The left-hand side of the operation. 941 | CalculationValue left = 2; 942 | 943 | // The right-hand side of the operation. 944 | CalculationValue right = 3; 945 | } 946 | } 947 | 948 | // The value itself. Mandatory. 949 | // 950 | // This is wrapped in a message type rather than used directly to reduce 951 | // repetition, and because oneofs can't be repeated. 952 | oneof value { 953 | String string = 1; 954 | Number number = 2; 955 | RgbColor rgb_color = 3; 956 | HslColor hsl_color = 4; 957 | List list = 5; 958 | Map map = 6; 959 | SingletonValue singleton = 7; 960 | CompilerFunction compiler_function = 8; 961 | HostFunction host_function = 9; 962 | ArgumentList argument_list = 10; 963 | HwbColor hwb_color = 11; 964 | Calculation calculation = 12; 965 | } 966 | } 967 | 968 | // Different types of separators a list can have. 969 | enum ListSeparator { 970 | // List elements are separated by a comma. 971 | COMMA = 0; 972 | 973 | // List elements are separated by whitespace. 974 | SPACE = 1; 975 | 976 | // List elements are separated by a forward slash. 977 | SLASH = 2; 978 | 979 | // The list's separator hasn't yet been determined. This is only allowed for 980 | // singleton and empty lists. 981 | // 982 | // Singleton lists and empty lists don't have separators defined. This means 983 | // that list functions will prefer other lists' separators if possible. 984 | UNDECIDED = 3; 985 | } 986 | 987 | // Singleton SassScript values that have no internal state. 988 | enum SingletonValue { 989 | // The SassScript boolean true value. 990 | TRUE = 0; 991 | 992 | // The SassScript boolean false value. 993 | FALSE = 1; 994 | 995 | // The SassScript null value. 996 | NULL = 2; 997 | } 998 | 999 | // An operator used in a calculation value's operation. 1000 | enum CalculationOperator { 1001 | // The addition operator. 1002 | PLUS = 0; 1003 | 1004 | // The subtraction operator. 1005 | MINUS = 1; 1006 | 1007 | // The multiplication operator. 1008 | TIMES = 2; 1009 | 1010 | // The division operator. 1011 | DIVIDE = 3; 1012 | } 1013 | --------------------------------------------------------------------------------