├── 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 |
--------------------------------------------------------------------------------