Document the new JS API (#3183)

This commit is contained in:
Natalie Weizenbaum 2021-11-30 15:32:04 -08:00 committed by GitHub
parent ebbc52877a
commit b192519b55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1628 additions and 80 deletions

View File

@ -1,15 +1,75 @@
Both [Dart Sass] and [LibSass] support the same JavaScript API. Dart Sass is
distributed as the pure-Javascript [`sass` package], and LibSass is distributed
as a native extension in the [`node-sass` package].
The [`sass` package] on npm is a pure-JavaScript package built from the [Dart
Sass] implementation. In addition to Dart Sass's [command-line interface], it
provides a JavaScript API that can be used to drive Sass compilations from
JavaScript. It even allows an application to control {@link Options.importers |
how stylesheets are loaded} and {@link Options.functions | define custom
functions}.
[Dart Sass]: https://sass-lang.com/dart-sass
[LibSass]: https://sass-lang.com/libsass
[`sass` package]: https://www.npmjs.com/package/sass
[`node-sass` package]: https://www.npmjs.com/package/node-sass
[Dart Sass]: https://sass-lang.com/dart-sass
[command-line interface]: https://sass-lang.com/documentation/cli/dart-sass
## Usage
The JavaScript API has two entrypoints for compiling Sass to CSS. Each one can
The JavaScript API provides two entrypoints for compiling Sass to CSS, each of
which has a synchronous variant that returns a plain [[CompileResult]] and an
asynchronous variant that returns a `Promise`. **The asynchronous variants are
much slower,** but they allow custom importers and functions to run
asynchronously.
* [[compile]] and [[compileAsync]] take a path to a Sass file and return the
result of compiling that file to CSS.
```js
const sass = require('sass');
const result = sass.compile("style.scss");
console.log(result.css);
```
* [[compileString]] and [[compileStringAsync]] take a string that represents the
contents of a Sass file and return the result of compiling that file to CSS.
```js
const sass = require('sass');
const result = sass.compileString(`
h1 {
font-size: 40px;
code {
font-face: Roboto Mono;
}
}`);
console.log(result.css);
```
## Integrations
Most popular Node.js build systems have integrations available for the JS API:
* Webpack uses the [`sass-loader` package].
* Gulp uses the [`gulp-sass` package].
* Broccoli uses the [`broccoli-sass-source-maps` package].
* Ember uses the [`ember-cli-sass` package].
* Grunt uses the [`grunt-sass` package].
[`sass-loader` package]: https://www.npmjs.com/package/sass-loader
[`gulp-sass` package]: https://www.npmjs.com/package/gulp-sass
[`broccoli-sass-source-maps` package]: https://www.npmjs.com/package/broccoli-sass-source-maps
[`ember-cli-sass` package]: https://www.npmjs.com/package/ember-cli-sass
[`grunt-sass` package]: https://www.npmjs.com/package/grunt-sass
## Legacy API
The `sass` package also supports an older API. Although this API is deprecated,
it will continue to be supported until the release of version 2.0.0 of the
`sass` package. The legacy API is also supported by the [`node-sass` package],
which is a native extension wrapper for the deprecated [LibSass] implementation.
[`node-sass` package]: https://www.npmjs.com/package/node-sass
[LibSass]: https://sass-lang.com/libsass
The legacy API has two entrypoints for compiling Sass to CSS. Each one can
compile either a Sass file by passing in [[LegacyFileOptions]] or a string of
Sass code by passing in a [[LegacyStringOptions]].
@ -41,20 +101,3 @@ Sass code by passing in a [[LegacyStringOptions]].
}
});
```
## Integrations
Most popular Node.js build systems have integrations available for the JS API:
* Webpack uses the [`sass-loader` package].
* Gulp uses the [`gulp-sass` package].
* Broccoli uses the [`broccoli-sass-source-maps` package].
* Ember uses the [`ember-cli-sass` package].
* Grunt uses the [`grunt-sass` package].
[`sass-loader` package]: https://www.npmjs.com/package/sass-loader
[`gulp-sass` package]: https://www.npmjs.com/package/gulp-sass
[`broccoli-sass-source-maps` package]: https://www.npmjs.com/package/broccoli-sass-source-maps
[`ember-cli-sass` package]: https://www.npmjs.com/package/ember-cli-sass
[`grunt-sass` package]: https://www.npmjs.com/package/grunt-sass

View File

@ -3,28 +3,150 @@ import {RawSourceMap} from 'source-map-js';
import {Options, StringOptions} from './options';
/**
* The result of compiling Sass to CSS. Returned by [[compile]],
* [[compileAsync]], [[compileString]], and [[compileStringAsync]].
*
* @category Compile
*/
export interface CompileResult {
/**
* The generated CSS.
*
* Note that this *never* includes a `sourceMapUrl` commentit's up to the
* caller to determine where to save the source map and how to link to it from
* the stylesheet.
*/
css: string;
/**
* The canonical URLs of all the stylesheets that were loaded during the
* Sass compilation. The order of these URLs is not guaranteed.
*/
loadedUrls: URL[];
/**
* The object representation of the source map that maps locations in the
* generated CSS back to locations in the Sass source code.
*
* This typically uses absolute `file:` URLs to refer to Sass files, although
* this can be controlled by having a custom [[Importer]] return
* [[ImporterResult.sourceMapUrl]].
*
* This is set if and only if [[Options.sourceMap]] is `true`.
*/
sourceMap?: RawSourceMap;
}
/** @hidden */
/**
* Synchronously compiles the Sass file at `path` to CSS. If it succeeds it
* returns a [[CompileResult]], and if it fails it throws an [[Exception]].
*
* This only allows synchronous [[Importer]]s and [[CustomFunction]]s.
*
* @example
*
* ```js
* const sass = require('sass');
*
* const result = sass.compile("style.scss");
* console.log(result.css);
* ```
*
* @category Compile
* @compatibility dart: "1.45.0", node: false
*/
export function compile(path: string, options?: Options<'sync'>): CompileResult;
/** @hidden */
/**
* Asynchronously compiles the Sass file at `path` to CSS. Returns a promise
* that resolves with a [[CompileResult]] if it succeeds and rejects with an
* [[Exception]] if it fails.
*
* This only allows synchronous or asynchronous [[Importer]]s and
* [[CustomFunction]]s.
*
* **Heads up!** When using Dart Sass, **[[compile]] is almost twice as fast as
* [[compileAsync]]**, due to the overhead of making the entire evaluation
* process asynchronous.
*
* @example
*
* ```js
* const sass = require('sass');
*
* const result = await sass.compileAsync("style.scss");
* console.log(result.css);
* ```
*
* @category Compile
* @compatibility dart: "1.45.0", node: false
*/
export function compileAsync(
path: string,
options?: Options<'async'>
): Promise<CompileResult>;
/** @hidden */
/**
* Synchronously compiles a stylesheet whose contents is `source` to CSS. If it
* succeeds it returns a [[CompileResult]], and if it fails it throws an
* [[Exception]].
*
* This only allows synchronous [[Importer]]s and [[CustomFunction]]s.
*
* @example
*
* ```js
* const sass = require('sass');
*
* const result = sass.compileString(`
* h1 {
* font-size: 40px;
* code {
* font-face: Roboto Mono;
* }
* }`);
* console.log(result.css);
* ```
*
* @category Compile
* @compatibility dart: "1.45.0", node: false
*/
export function compileString(
source: string,
options?: StringOptions<'sync'>
): CompileResult;
/** @hidden */
/**
* Asynchronously compiles a stylesheet whose contents is `source` to CSS.
* Returns a promise that resolves with a [[CompileResult]] if it succeeds and
* rejects with an [[Exception]] if it fails.
*
* This only allows synchronous or asynchronous [[Importer]]s and
* [[CustomFunction]]s.
*
* **Heads up!** When using Dart Sass, **[[compile]] is almost twice as fast as
* [[compileAsync]]**, due to the overhead of making the entire evaluation
* process asynchronous.
*
* @example
*
* ```js
* const sass = require('sass');
*
* const result = await sass.compileStringAsync(`
* h1 {
* font-size: 40px;
* code {
* font-face: Roboto Mono;
* }
* }`);
* console.log(result.css);
* ```
*
* @category Compile
* @compatibility dart: "1.45.0", node: false
*/
export function compileStringAsync(
source: string,
options?: StringOptions<'async'>

View File

@ -1,13 +1,41 @@
import {SourceSpan} from './logger';
/**
* An exception thrown because a Sass compilation failed.
*
* @category Other
*/
export class Exception extends Error {
private constructor();
/**
* A human-friendly representation of the exception.
*
* Because many tools simply print `Error.message` directly, this includes not
* only the textual description of what went wrong (the [[sassMessage]]) but
* also an indication of where in the Sass stylesheet the error occurred (the
* [[span]]) and the Sass stack trace at the point of error (the
* [[sassStack]]).
*/
message: string;
sassMessage: string;
/**
* A textual description of what went wrong.
*
* Unlike [[message]], this does *not* include representations of [[span]] or
* [[sassStack]].
*/
readonly sassMessage: string;
sassStack: string;
/**
* A human-friendly representation of the Sass stack trace at the point of
* error.
*/
readonly sassStack: string;
span: SourceSpan;
/** The location the error occurred in the Sass file that triggered it. */
readonly span: SourceSpan;
/** Returns the same string as [[message]]. */
toString(): string;
}

View File

@ -3,32 +3,294 @@ import {URL} from 'url';
import {Syntax} from './options';
import {PromiseOr} from './util/promise_or';
/**
* A special type of importer that redirects all loads to existing files on
* disk. Although this is less powerful than a full [[Importer]], it
* automatically takes care of Sass features like resolving partials and file
* extensions and of loading the file from disk.
*
* Like all importers, this implements custom Sass loading logic for [`@use`
* rules](https://sass-lang.com/documentation/at-rules/use) and [`@import`
* rules](https://sass-lang.com/documentation/at-rules/import). It can be passed
* to [[Options.importers]] or [[StringOptionsWithImporter.importer]].
*
* @typeParam sync - A `FileImporter<'sync'>`'s [[findFileUrl]] must return
* synchronously, but in return it can be passed to [[compile]] and
* [[compileString]] in addition to [[compileAsync]] and [[compileStringAsync]].
*
* A `FileImporter<'async'>`'s [[findFileUrl]] may either return synchronously
* or asynchronously, but it can only be used with [[compileAsync]] and
* [[compileStringAsync]].
*
* @example
*
* ```js
* const {fileURLToPath} = require('url');
*
* sass.compile('style.scss', {
* importers: [{
* // An importer that redirects relative URLs starting with "~" to
* // `node_modules`.
* findFileUrl(url) {
* if (!url.startsWith('~')) return null;
* return new URL(url.substring(1), pathToFileURL('node_modules'));
* }
* }]
* });
* ```
*
* @category Importer
*/
export interface FileImporter<
sync extends 'sync' | 'async' = 'sync' | 'async'
> {
/**
* A callback that's called to partially resolve a load (such as
* [`@use`](https://sass-lang.com/documentation/at-rules/use) or
* [`@import`](https://sass-lang.com/documentation/at-rules/import)) to a file
* on disk.
*
* Unlike an [[Importer]], the compiler will automatically handle relative
* loads for a [[FileImporter]]. See [[Options.importers]] for more details on
* the way loads are resolved.
*
* @param url - The loaded URL. Since this might be relative, it's represented
* as a string rather than a [[URL]] object.
*
* @param options.fromImport - Whether this is being invoked because of a Sass
* `@import` rule, as opposed to a `@use` or `@forward` rule.
*
* This should *only* be used for determining whether or not to load
* [import-only files](https://sass-lang.com/documentation/at-rules/import#import-only-files).
*
* @returns An absolute `file:` URL if this importer recognizes the `url`.
* This may be only partially resolved: the compiler will automatically look
* for [partials](https://sass-lang.com/documentation/at-rules/use#partials),
* [index files](https://sass-lang.com/documentation/at-rules/use#index-files),
* and file extensions based on the returned URL. An importer may also return
* a fully resolved URL if it so chooses.
*
* If this importer doesn't recognize the URL, it should return `null` instead
* to allow other importers or {@link Options.loadPaths | load paths} to
* handle it.
*
* This may also return a `Promise`, but if it does the importer may only be
* passed to [[compileAsync]] and [[compileStringAsync]], not [[compile]] or
* [[compileString]].
*
* @throws any - If this importer recognizes `url` but determines that it's
* invalid, it may throw an exception that will be wrapped by Sass. If the
* exception object has a `message` property, it will be used as the wrapped
* exception's message; otherwise, the exception object's `toString()` will be
* used. This means it's safe for importers to throw plain strings.
*/
findFileUrl(
url: string,
options: {fromImport: boolean}
): PromiseOr<URL | null, sync>;
/** @hidden */
canonicalize?: never;
}
/**
* An object that implements custom Sass loading logic for [`@use`
* rules](https://sass-lang.com/documentation/at-rules/use) and [`@import`
* rules](https://sass-lang.com/documentation/at-rules/import). It can be passed
* to [[Options.importers]] or [[StringOptionsWithImporter.importer]].
*
* Importers that simply redirect to files on disk are encouraged to use the
* [[FileImporter]] interface instead.
*
* See [[Options.importers]] for more details on the way loads are resolved.
*
* @typeParam sync - An `Importer<'sync'>`'s [[canonicalize]] and [[load]] must
* return synchronously, but in return it can be passed to [[compile]] and
* [[compileString]] in addition to [[compileAsync]] and [[compileStringAsync]].
*
* An `Importer<'async'>`'s [[canonicalize]] and [[load]] may either return
* synchronously or asynchronously, but it can only be used with
* [[compileAsync]] and [[compileStringAsync]].
*
* @example Resolving a Load
*
* This is the process of resolving a load using a custom importer:
*
* - The compiler encounters `@use "db:foo/bar/baz"`.
* - It calls [[canonicalize]] with `"db:foo/bar/baz"`.
* - [[canonicalize]] returns `new URL("db:foo/bar/baz/_index.scss")`.
* - If the compiler has already loaded a stylesheet with this canonical URL, it
* re-uses the existing module.
* - Otherwise, it calls [[load]] with `new URL("db:foo/bar/baz/_index.scss")`.
* - [[load]] returns an [[ImporterResult]] that the compiler uses as the
* contents of the module.
*
* @example Code Sample
*
* ```js
* sass.compile('style.scss', {
* // An importer for URLs like `bgcolor:orange` that generates a
* // stylesheet with the given background color.
* importers: [{
* canonicalize(url) {
* if (!url.startsWith('bgcolor:')) return null;
* return new URL(url);
* },
* load(canonicalUrl) {
* return {
* contents: `body {background-color: ${canonicalUrl.pathname}}`,
* syntax: 'scss'
* };
* }
* }]
* });
* ```
*
* @category Importer
*/
export interface Importer<sync extends 'sync' | 'async' = 'sync' | 'async'> {
/**
* If `url` is recognized by this importer, returns its canonical format.
*
* If Sass has already loaded a stylesheet with the returned canonical URL, it
* re-uses the existing parse tree (and the loaded module for `@use`). This
* means that importers **must ensure** that the same canonical URL always
* refers to the same stylesheet, *even across different importers*. As such,
* importers are encouraged to use unique URL schemes to disambiguate between
* one another.
*
* As much as possible, custom importers should canonicalize URLs the same way
* as the built-in filesystem importer:
*
* - The importer should look for stylesheets by adding the prefix `_` to the
* URL's basename, and by adding the extensions `.sass` and `.scss` if the
* URL doesn't already have one of those extensions. For example, if the
* URL was `foo/bar/baz`, the importer would look for:
* - `foo/bar/baz.sass`
* - `foo/bar/baz.scss`
* - `foo/bar/_baz.sass`
* - `foo/bar/_baz.scss`
*
* If the URL was `foo/bar/baz.scss`, the importer would just look for:
* - `foo/bar/baz.scss`
* - `foo/bar/_baz.scss`
*
* If the importer finds a stylesheet at more than one of these URLs, it
* should throw an exception indicating that the URL is ambiguous. Note that
* if the extension is explicitly specified, a stylesheet with the opposite
* extension is allowed to exist.
*
* - If none of the possible paths is valid, the importer should perform the
* same resolution on the URL followed by `/index`. In the example above,
* it would look for:
* - `foo/bar/baz/index.sass`
* - `foo/bar/baz/index.scss`
* - `foo/bar/baz/_index.sass`
* - `foo/bar/baz/_index.scss`
*
* As above, if the importer finds a stylesheet at more than one of these
* URLs, it should throw an exception indicating that the import is
* ambiguous.
*
* If no stylesheets are found, the importer should return `null`.
*
* Calling [[canonicalize]] multiple times with the same URL must return the
* same result. Calling [[canonicalize]] with a URL returned by a previous
* call to [[canonicalize]] must return that URL.
*
* Relative loads in stylesheets loaded from an importer are handled by
* resolving the loaded URL relative to the canonical URL of the stylesheet
* that contains it, and passing that URL back to the importer's
* [[canonicalize]] method. For example, suppose the "Resolving a Load"
* example {@link Importer | above} returned a stylesheet that contained
* `@use "mixins"`:
*
* - The compiler resolves the URL `mixins` relative to the current
* stylesheet's canonical URL `db:foo/bar/baz/_index.scss` to get
* `db:foo/bar/baz/mixins`.
* - It calls [[canonicalize]] with `"db:foo/bar/baz/mixins"`.
* - [[canonicalize]] returns `new URL("db:foo/bar/baz/_mixins.scss")`.
*
* Because of this, [[canonicalize]] must return a meaningful result when
* called with a URL relative to one returned by an earlier call to
* [[canonicalize]].
*
* @param url - The loaded URL. Since this might be relative, it's represented
* as a string rather than a [[URL]] object.
*
* @param options.fromImport - Whether this is being invoked because of a Sass
* `@import` rule, as opposed to a `@use` or `@forward` rule.
*
* This should *only* be used for determining whether or not to load
* [import-only files](https://sass-lang.com/documentation/at-rules/import#import-only-files).
*
* @returns An absolute URL if this importer recognizes the `url`, or `null`
* if it doesn't. If this returns `null`, other importers or {@link
* Options.loadPaths | load paths} may handle the load.
*
* This may also return a `Promise`, but if it does the importer may only be
* passed to [[compileAsync]] and [[compileStringAsync]], not [[compile]] or
* [[compileString]].
*
* @throws any - If this importer recognizes `url` but determines that it's
* invalid, it may throw an exception that will be wrapped by Sass. If the
* exception object has a `message` property, it will be used as the wrapped
* exception's message; otherwise, the exception object's `toString()` will be
* used. This means it's safe for importers to throw plain strings.
*/
canonicalize(
url: string,
options: {fromImport: boolean}
): PromiseOr<URL | null, sync>;
/**
* Loads the Sass text for the given `canonicalUrl`, or returns `null` if this
* importer can't find the stylesheet it refers to.
*
* @param canonicalUrl - The canonical URL of the stylesheet to load. This is
* guaranteed to come from a call to [[canonicalize]], although not every call
* to [[canonicalize]] will result in a call to [[load]].
*
* @returns The contents of the stylesheet at `canonicalUrl` if it can be
* loaded, or `null` if it can't.
*
* This may also return a `Promise`, but if it does the importer may only be
* passed to [[compileAsync]] and [[compileStringAsync]], not [[compile]] or
* [[compileString]].
*
* @throws any - If this importer finds a stylesheet at `url` but it fails to
* load for some reason, or if `url` is uniquely associated with this importer
* but doesn't refer to a real stylesheet, the importer may throw an exception
* that will be wrapped by Sass. If the exception object has a `message`
* property, it will be used as the wrapped exception's message; otherwise,
* the exception object's `toString()` will be used. This means it's safe for
* importers to throw plain strings.
*/
load(canonicalUrl: URL): PromiseOr<ImporterResult | null, sync>;
/** @hidden */
findFileUrl?: never;
}
/**
* The result of successfully loading a stylesheet with an [[Importer]].
*
* @category Importer
*/
export interface ImporterResult {
/** The contents of the stylesheet. */
contents: string;
/** The syntax with which to parse [[contents]]. */
syntax: Syntax;
/**
* The URL to use to link to the loaded stylesheet's source code in source
* maps. A `file:` URL is ideal because it's accessible to both browsers and
* other build tools, but an `http:` URL is also acceptable.
*
* If this isn't set, it defaults to a `data:` URL that contains the contents
* of the loaded stylesheet.
*/
sourceMapUrl?: URL;
}

View File

@ -2,7 +2,6 @@
// written to provide user-facing documentation rather than to specify behavior for
// implementations.
/** @hidden */
export {
CompileResult,
compile,
@ -10,22 +9,19 @@ export {
compileString,
compileStringAsync,
} from './compile';
/** @hidden */
export {Exception} from './exception';
/** @hidden */
export {FileImporter, Importer, ImporterResult} from './importer';
export {Logger, SourceSpan, SourceLocation} from './logger';
/** @hidden */
export {
CustomFunction,
Options,
OutputStyle,
StringOptions,
StringOptionsWithImporter,
StringOptionsWithoutImporter,
Syntax,
} from './options';
/** @hidden */
export {PromiseOr} from './util/promise_or';
/** @hidden */
export {
ListSeparator,
SassArgumentList,

View File

@ -1,6 +1,11 @@
/**
* The exception type thrown by [[renderSync]] and passed as the error to
* [[render]]'s callback.
*
* @category Legacy
* @deprecated This is only thrown by the legacy [[render]] and [[renderSync]]
* APIs. Use [[compile]], [[compileString]], [[compileAsync]], and
* [[compileStringAsync]] instead.
*/
export interface LegacyException extends Error {
/**

View File

@ -28,6 +28,11 @@ import {LegacyPluginThis} from './plugin_this';
* that's passed to [[LegacySharedOptions.functions]]. If the signature [takes
* arbitrary arguments](https://sass-lang.com/documentation/at-rules/function#taking-arbitrary-arguments),
* they're passed as a single argument list in the last argument.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[CustomFunction]] with [[compile]], [[compileString]],
* [[compileAsync]], and [[compileStringAsync]] instead.
*/
export type LegacySyncFunction = (
this: LegacyPluginThis,
@ -68,6 +73,11 @@ export type LegacySyncFunction = (
* arbitrary arguments](https://sass-lang.com/documentation/at-rules/function#taking-arbitrary-arguments),
* they're passed as a single argument list in the last argument before the
* callback.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[CustomFunction]] with [[compile]], [[compileString]],
* [[compileAsync]], and [[compileStringAsync]] instead.
*/
export type LegacyAsyncFunction = (
this: LegacyPluginThis,
@ -81,6 +91,11 @@ export type LegacyAsyncFunction = (
* [[LegacyAsyncFunction]] which calls a callback with its result.
*
* See [[LegacySharedOptions.functions]] for more details.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[CustomFunction]] with [[compile]], [[compileString]],
* [[compileAsync]], and [[compileStringAsync]] instead.
*/
export type LegacyFunction<sync extends 'sync' | 'async'> = sync extends 'async'
? LegacySyncFunction | LegacyAsyncFunction
@ -89,6 +104,11 @@ export type LegacyFunction<sync extends 'sync' | 'async'> = sync extends 'async'
/**
* A type representing all the possible values that may be passed to or returned
* from a [[LegacyFunction]].
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Value]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
export type LegacyValue =
| types.Null
@ -99,7 +119,14 @@ export type LegacyValue =
| types.List
| types.Map;
/** The namespace for value types used in the legacy function API. */
/**
* The namespace for value types used in the legacy function API.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Value]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
export namespace types {
/**
* The class for Sass's singleton [`null`

View File

@ -1,6 +1,13 @@
import {LegacyPluginThis} from './plugin_this';
/** The value of `this` in the context of a [[LegacyImporter]] function. */
/**
* The value of `this` in the context of a [[LegacyImporter]] function.
*
* @category Legacy
* @deprecated This is only used by the legacy [[render]] and [[renderSync]]
* APIs. Use [[Importer]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
interface LegacyImporterThis extends LegacyPluginThis {
/**
* Whether the importer is being invoked because of a Sass `@import` rule, as
@ -29,6 +36,11 @@ interface LegacyImporterThis extends LegacyPluginThis {
*
* * An [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
* object, indicating that importing failed.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[ImporterResult]] with [[compile]], [[compileString]],
* [[compileAsync]], and [[compileStringAsync]] instead.
*/
export type LegacyImporterResult =
| {file: string}
@ -71,6 +83,11 @@ export type LegacyImporterResult =
* * If the stylesheet was loaded from an importer that returned its contents,
* its the URL of the `@use` or `@import` rule that loaded it.
* * If the stylesheet came from the data option, its the string "stdin".
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Importer]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
type LegacySyncImporter = (
this: LegacyImporterThis,
@ -118,6 +135,11 @@ type LegacySyncImporter = (
* * If the stylesheet came from the data option, its the string "stdin".
*
* @param done - The callback to call once the importer has finished running.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Importer]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
type LegacyAsyncImporter = (
this: LegacyImporterThis,
@ -135,6 +157,11 @@ type LegacyAsyncImporter = (
* [[LegacyAsyncImporter]] which calls a callback with its result.
*
* See [[LegacySharedOptions.importer]] for more details.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Importer]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
export type LegacyImporter<sync = 'sync' | 'async'> = sync extends 'async'
? LegacySyncImporter | LegacyAsyncImporter

View File

@ -9,6 +9,11 @@ import {LegacyFunction} from './function';
* @typeParam sync - This lets the TypeScript checker verify that
* [[LegacyAsyncImporter]]s and [[LegacyAsyncFunction]]s aren't passed to
* [[renderSync]].
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Options]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
export interface LegacySharedOptions<sync extends 'sync' | 'async'> {
/**
@ -157,7 +162,7 @@ export interface LegacySharedOptions<sync extends 'sync' | 'async'> {
* }
* }`;
*
* const result = sass.renderSync({
* let result = sass.renderSync({
* data: source,
* outputStyle: "expanded"
* });
@ -218,7 +223,7 @@ export interface LegacySharedOptions<sync extends 'sync' | 'async'> {
* @example
*
* ```js
* const result = sass.renderSync({
* let result = sass.renderSync({
* file: "style.scss",
* sourceMap: "out.map"
* })
@ -558,6 +563,11 @@ export interface LegacyFileOptions<sync extends 'sync' | 'async'>
* @typeParam sync - This lets the TypeScript checker verify that
* [[LegacyAsyncImporter]]s and [[LegacyAsyncFunction]]s aren't passed to
* [[renderSync]].
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[StringOptions]] with [[compile]], [[compileString]],
* [[compileAsync]], and [[compileStringAsync]] instead.
*/
export interface LegacyStringOptions<sync extends 'sync' | 'async'>
extends LegacySharedOptions<sync> {
@ -621,6 +631,11 @@ export interface LegacyStringOptions<sync extends 'sync' | 'async'>
*
* See [[LegacySharedOptions]] for options that are shared across both file and
* string inputs.
*
* @category Legacy
* @deprecated This only works with the legacy [[render]] and [[renderSync]]
* APIs. Use [[Options]] with [[compile]], [[compileString]], [[compileAsync]],
* and [[compileStringAsync]] instead.
*/
export type LegacyOptions<sync extends 'sync' | 'async'> =
| LegacyFileOptions<sync>

View File

@ -1,6 +1,11 @@
/**
* The value of `this` in the context of a [[LegacyImporter]] or
* [[LegacyFunction]] callback.
*
* @category Legacy
* @deprecated This is only used by the legacy [[render]] and [[renderSync]]
* APIs. Use [[compile]], [[compileString]], [[compileAsync]], and
* [[compileStringAsync]] instead.
*/
export interface LegacyPluginThis {
/**

View File

@ -4,6 +4,11 @@ import {LegacyOptions} from './options';
/**
* The object returned by [[render]] and [[renderSync]] after a successful
* compilation.
*
* @category Legacy
* @deprecated This is only used by the legacy [[render]] and [[renderSync]]
* APIs. Use [[compile]], [[compileString]], [[compileAsync]], and
* [[compileStringAsync]] instead.
*/
export interface LegacyResult {
/**
@ -99,6 +104,9 @@ export interface LegacyResult {
* const result = sass.renderSync({file: "style.scss"});
* // ...
* ```
*
* @category Legacy
* @deprecated Use [[compile]] or [[compileString]] instead.
*/
export function renderSync(options: LegacyOptions<'sync'>): LegacyResult;
@ -121,6 +129,9 @@ export function renderSync(options: LegacyOptions<'sync'>): LegacyResult;
* // ...
* });
* ```
*
* @category Legacy
* @deprecated Use [[compileAsync]] or [[compileStringAsync]] instead.
*/
export function render(
options: LegacyOptions<'async'>,

View File

@ -30,6 +30,8 @@ export {SourceSpan} from './source_span';
*
* fs.writeFileSync('log.txt', log);
* ```
*
* @category Logger
*/
export interface Logger {
/**
@ -70,6 +72,7 @@ export interface Logger {
/**
* A namespace for built-in [[Logger]]s.
*
* @category Logger
* @compatibility dart: "1.43.0", node: false
*/
export namespace Logger {

View File

@ -1,7 +1,21 @@
/**
* A specific location within a source file.
*
* This is always associated with a [[SourceSpan]] which indicates *which* file
* it refers to.
*
* @category Logger
*/
export interface SourceLocation {
/**
* The 0-based index of this location within its source file, in terms of
* UTF-16 code units.
*/
offset: number;
/** The 0-based line number of this location. */
line: number;
/** The 0-based column number of this location. */
column: number;
}

View File

@ -2,14 +2,35 @@ import {URL} from 'url';
import {SourceLocation} from './source_location';
/**
* A span of text within a source file.
*
* @category Logger
*/
export interface SourceSpan {
/** The beginning of this span, inclusive. */
start: SourceLocation;
/**
* The end of this span, exclusive.
*
* If [[start]] and [[end]] refer to the same location, the span has zero
* length and refers to the point immediately after [[start]] and before the
* next character.
*/
end: SourceLocation;
/** The canonical URL of the file this span refers to. */
url?: URL;
/** The text covered by the span. */
text: string;
/**
* Text surrounding the span.
*
* If this is set, it must include only whole lines, and it must include at
* least all line(s) which are partially covered by this span.
*/
context?: string;
}

View File

@ -5,44 +5,406 @@ import {Logger} from './logger';
import {Value} from './value';
import {PromiseOr} from './util/promise_or';
/**
* Syntaxes supported by Sass:
*
* - `'scss'` is the [SCSS
* syntax](https://sass-lang.com/documentation/syntax#scss).
* - `'indented'` is the [indented
* syntax](https://sass-lang.com/documentation/syntax#the-indented-syntax)
* - `'css'` is plain CSS, which is parsed like SCSS but forbids the use of any
* special Sass features.
*
* @category Options
*/
export type Syntax = 'scss' | 'indented' | 'css';
/**
* Possible output styles for the compiled CSS:
*
* - `"expanded"` (the default for Dart Sass) writes each selector and
* declaration on its own line.
*
* - `"compressed"` removes as many extra characters as possible, and writes
* the entire stylesheet on a single line.
*
* @category Options
*/
export type OutputStyle = 'expanded' | 'compressed';
/**
* A callback that implements a custom Sass function. This can be passed to
* [[Options.functions]].
*
* ```js
* const result = sass.compile('style.scss', {
* functions: {
* "sum($arg1, $arg2)": (args) => {
* const value1 = args[0].assertNumber('arg1').value;
* const value2 = args[1].assertNumber('arg2')
* .convertValueToMatch(arg1, 'arg2', 'arg1');
* return new sass.SassNumber(value1 + value2).coerceToMatch(arg1);
* }
* }
* });
* ```
*
* @typeParam sync - A `CustomFunction<'sync'>` must return synchronously, but
* in return it can be passed to [[compile]] and [[compileString]] in addition
* to [[compileAsync]] and [[compileStringAsync]].
*
* A `CustomFunction<'async'>` may either return synchronously or
* asynchronously, but it can only be used with [[compileAsync]] and
* [[compileStringAsync]].
*
* @param args - An array of arguments passed by the function's caller. If the
* function takes [arbitrary
* arguments](https://sass-lang.com/documentation/at-rules/function#taking-arbitrary-arguments),
* the last element will be a [[SassArgumentList]].
*
* @returns The function's result. This may be in the form of a `Promise`, but
* if it is the function may only be passed to [[compileAsync]] and
* [[compileStringAsync]], not [[compile]] or [[compileString]].
*
* @throws any - This function may throw an error, which the Sass compiler will
* treat as the function call failing. If the exception object has a `message`
* property, it will be used as the wrapped exception's message; otherwise, the
* exception object's `toString()` will be used. This means it's safe for custom
* functions to throw plain strings.
*
* @category Custom Function
*/
export type CustomFunction<sync extends 'sync' | 'async'> = (
args: Value[]
) => PromiseOr<Value, sync>;
/**
* Options that can be passed to [[compile]], [[compileAsync]],
* [[compileString]], or [[compileStringAsync]].
*
* @typeParam sync - This lets the TypeScript checker verify that asynchronous
* [[Importer]]s, [[FileImporter]]s, and [[CustomFunction]]s aren't passed to
* [[compile]] or [[compileString]].
*
* @category Options
*/
export interface Options<sync extends 'sync' | 'async'> {
/**
* If this is `true`, the compiler will exclusively use ASCII characters in
* its error and warning messages. Otherwise, it may use non-ASCII Unicode
* characters as well.
*
* @defaultValue `false`
* @category Messages
*/
alertAscii?: boolean;
/**
* If this is `true`, the compiler will use ANSI color escape codes in its
* error and warning messages. If it's `false`, it won't use these. If it's
* undefined, the compiler will determine whether or not to use colors
* depending on whether the user is using an interactive terminal.
*
* @category Messages
*/
alertColor?: boolean;
/**
* Additional built-in Sass functions that are available in all stylesheets.
* This option takes an object whose keys are Sass function signatures like
* you'd write for the [`@function
* rule`](https://sass-lang.com/documentation/at-rules/function) and whose
* values are [[CustomFunction]]s.
*
* Functions are passed JavaScript representations of [Sass value
* types](https://sass-lang.com/documentation/js-api#value-types), and must
* return the same.
*
* When writing custom functions, it's important to make them as user-friendly
* and as close to the standards set by Sass's core functions as possible. Some
* good guidelines to follow include:
*
* * Use `Value.assert*` methods, like [[Value.assertString]], to cast untyped
* `Value` objects to more specific types. For values that were passed
* directly as arguments, pass in the argument name as well. This ensures
* that the user gets good error messages when they pass in the wrong type
* to your function.
*
* * Individual classes may have more specific `assert*` methods, like
* [[SassNumber.assertInt]], which should be used when possible.
*
* * In Sass, every value counts as a list. Rather than trying to detect the
* [[SassList]] type, you should use [[Value.asList]] to treat all values as
* lists.
*
* * When manipulating values like lists, strings, and numbers that have
* metadata (comma versus space separated, bracketed versus unbracketed,
* quoted versus unquoted, units), the output metadata should match the
* input metadata.
*
* * When in doubt, lists should default to comma-separated, strings should
* default to quoted, and numbers should default to unitless.
*
* * In Sass, lists and strings use one-based indexing and use negative
* indices to index from the end of value. Functions should follow these
* conventions. [[Value.sassIndexToListIndex]] and
* [[SassString.sassIndexToStringIndex]] can be used to do this
* automatically.
*
* * String indexes in Sass refer to Unicode code points while JavaScript
* string indices refer to UTF-16 code units. For example, the character
* U+1F60A SMILING FACE WITH SMILING EYES is a single Unicode code point but
* is represented in UTF-16 as two code units (`0xD83D` and `0xDE0A`). So in
* JavaScript, `"a😊b".charCodeAt(1)` returns `0xD83D`, whereas in Sass
* `str-slice("a😊b", 1, 1)` returns `"😊"`. Functions should follow Sass's
* convention. [[SassString.sassIndexToStringIndex]] can be used to do this
* automatically, and the [[SassString.sassLength]] getter can be used to
* access a string's length in code points.
*
* @example
*
* ```js
* sass.compileString(`
* h1 {
* font-size: pow(2, 5) * 1px;
* }`, {
* functions: {
* // Note: in real code, you should use `math.pow()` from the built-in
* // `sass:math` module.
* 'pow($base, $exponent)': function(args) {
* const base = args[0].assertNumber('base').assertNoUnits('base');
* const exponent =
* args[1].assertNumber('exponent').assertNoUnits('exponent');
*
* return new sass.SassNumber(Math.pow(base.value, exponent.value));
* }
* }
* });
* ```
*
* @category Plugins
*/
functions?: Record<string, CustomFunction<sync>>;
/**
* Custom importers that control how Sass resolves loads from rules like
* [`@use`](https://sass-lang.com/documentation/at-rules/use) and
* [`@import`](https://sass-lang.com/documentation/at-rules/import).
*
* Loads are resolved by trying, in order:
*
* - The importer that was used to load the current stylesheet, with the
* loaded URL resolved relative to the current stylesheet's canonical URL.
*
* - Each [[Importer]] or [[FileImporter]] in [[importers]], in order.
*
* - Each load path in [[loadPaths]], in order.
*
* If none of these return a Sass file, the load fails and Sass throws an
* error.
*
* @category Plugins
*/
importers?: (Importer<sync> | FileImporter<sync>)[];
/**
* Paths in which to look for stylesheets loaded by rules like
* [`@use`](https://sass-lang.com/documentation/at-rules/use) and
* [`@import`](https://sass-lang.com/documentation/at-rules/import).
*
* A load path `loadPath` is equivalent to the following [[FileImporter]]:
*
* ```js
* {
* findFileUrl(url) {
* // Load paths only support relative URLs.
* if (/^[a-z]+:/i.test(url)) return null;
* return new URL(url, pathToFileURL(loadPath));
* }
* }
* ```
*
* @category Input
*/
loadPaths?: string[];
/**
* An object to use to handle warnings and/or debug messages from Sass.
*
* By default, Sass emits warnings and debug messages to standard error, but
* if [[Logger.warn]] or [[Logger.debug]] is set, this will invoke them
* instead.
*
* The special value [[Logger.silent]] can be used to easily silence all
* messages.
*
* @category Messages
*/
logger?: Logger;
/**
* If this option is set to `true`, Sass wont print warnings that are caused
* by dependencies. A dependency is defined as any file thats loaded
* through [[loadPaths]] or [[importer]]. Stylesheets that are imported
* relative to the entrypoint are not considered dependencies.
*
* This is useful for silencing deprecation warnings that you cant fix on
* your own. However, please <em>also</em> notify your dependencies of the deprecations
* so that they can get fixed as soon as possible!
*
* **Heads up!** If [[compileString]] or [[compileStringAsync]] is called
* without [[StringWithoutImporter.url]], <em>all</em> stylesheets it loads
* will be considered dependencies. Since it doesnt have a path of its own,
* everything it loads is coming from a load path rather than a relative
* import.
*
* @defaultValue `false`
* @category Messages
*/
quietDeps?: boolean;
/**
* Whether or not Sass should generate a source map. If it does, the source
* map will be available as [[CompileResult.sourceMap]].
*
* **Heads up!** Sass doesn't automatically add a `sourceMappingURL` comment
* to the generated CSS. It's up to callers to do that, since callers have
* full knowledge of where the CSS and the source map will exist in relation
* to one another and how they'll be served to the browser.
*
* @defaultValue `false`
* @category Output
*/
sourceMap?: boolean;
/**
* The [[OutputStyle]] of the compiled CSS.
*
* @example
*
* ```js
* const source = `
* h1 {
* font-size: 40px;
* code {
* font-face: Roboto Mono;
* }
* }`;
*
* let result = sass.compileString(source, {style: "expanded"});
* console.log(result.css.toString());
* // h1 {
* // font-size: 40px;
* // }
* // h1 code {
* // font-face: Roboto Mono;
* // }
*
* result = sass.compileString(source, {style: "compressed"})
* console.log(result.css.toString());
* // h1{font-size:40px}h1 code{font-face:Roboto Mono}
* ```
*
* @category Output
*/
style?: OutputStyle;
/**
* By default, Dart Sass will print only five instances of the same
* deprecation warning per compilation to avoid deluging users in console
* noise. If you set `verbose` to `true`, it will instead print every
* deprecation warning it encounters.
*
* @defaultValue `false`
* @category Messages
*/
verbose?: boolean;
}
export type StringOptions<sync extends 'sync' | 'async'> = Options<sync> & {
/**
* Options that can be passed to [[compileString]] or [[compileStringAsync]].
*
* If the [[StringOptionsWithImporter.importer]] field isn't passed, the
* entrypoint file can't load files relative to itself and the [[url]] field is
* optional.
*
* @typeParam sync - This lets the TypeScript checker verify that asynchronous
* [[Importer]]s, [[FileImporter]]s, and [[CustomFunction]]s aren't passed to
* [[compile]] or [[compileString]].
*
* @category Options
*/
export interface StringOptionsWithoutImporter<sync extends 'sync' | 'async'>
extends Options<sync> {
/**
* The [[Syntax]] to use to parse the entrypoint stylesheet.
*
* @default `'scss'`
*
* @category Input
*/
syntax?: Syntax;
} & (
| {
url?: URL;
}
| {
importer: Importer<sync> | FileImporter<sync>;
url: URL;
}
);
/**
* The canonical URL of the entrypoint stylesheet. If this isn't passed along
* with [[StringOptionsWithoutImporter.importer]], it's optional and only used
* for error reporting.
*
* @category Input
*/
url?: URL;
}
/**
* Options that can be passed to [[compileString]] or [[compileStringAsync]].
*
* If the [[StringOptionsWithImporter.importer]] field is passed, the entrypoint
* file uses it to load files relative to itself and the [[url]] field is
* mandatory.
*
* @typeParam sync - This lets the TypeScript checker verify that asynchronous
* [[Importer]]s, [[FileImporter]]s, and [[CustomFunction]]s aren't passed to
* [[compile]] or [[compileString]].
*
* @category Options
*/
export interface StringOptionsWithImporter<sync extends 'sync' | 'async'>
extends StringOptionsWithoutImporter<sync> {
/**
* The importer to use to handle loads that are relative to the entrypoint
* stylesheet.
*
* A relative load's URL is first resolved relative to [[url]], then passed to
* [[importer]]. If the importer doesn't recognize it, it's then passed to
* [[importers]] and [[loadPaths]].
*
* @category Input
*/
importer: Importer<sync> | FileImporter<sync>;
/**
* The canonical URL of the entrypoint stylesheet. If this is passed along
* with [[importer]], it's used to resolve relative loads in the entrypoint
* stylesheet.
*
* @category Input
*/
url: URL;
}
/**
* Options that can be passed to [[compileString]] or [[compileStringAsync]].
*
* This is a [[StringOptionsWithImporter]] if it has a
* [[StringOptionsWithImporter.importer]] field, and a
* [[StringOptionsWithoutImporter]] otherwise.
*
* @typeParam sync - This lets the TypeScript checker verify that asynchronous
* [[Importer]]s, [[FileImporter]]s, and [[CustomFunction]]s aren't passed to
* [[compile]] or [[compileString]].
*
* @category Options
*/
export type StringOptions<sync extends 'sync' | 'async'> =
| StringOptionsWithImporter<sync>
| StringOptionsWithoutImporter<sync>;

View File

@ -1,7 +1,17 @@
/**
* A utility type for choosing between synchronous and asynchronous return
* values.
*
* This is used as the return value for plugins like [[CustomFunction]],
* [[Importer]], and [[FileImporter]] so that TypeScript enforces that
* asynchronous plugins are only passed to [[compileAsync]] and
* [[compileStringAsync]], not [[compile]] or [[compileString]].
*
* @typeParam sync - If this is `'sync'`, this can only be a `T`. If it's
* `'async'`, this can be either a `T` or a `Promise<T>`.
*
* @category Other
*/
export type PromiseOr<T, sync extends 'sync' | 'async'> = sync extends 'sync'
? T
: T | Promise<T>;
export type PromiseOr<T, sync extends 'sync' | 'async'> = sync extends 'async'
? T | Promise<T>
: T;

View File

@ -3,13 +3,45 @@ import {List, OrderedMap} from 'immutable';
import {Value} from './index';
import {SassList, ListSeparator} from './list';
/**
* Sass's [argument list
* type](https://sass-lang.com/documentation/values/lists#argument-lists).
*
* An argument list comes from a rest argument. It's distinct from a normal
* [[SassList]] in that it may contain a keyword map as well as the positional
* arguments.
*
* @category Custom Function
*/
export class SassArgumentList extends SassList {
/**
* Creates a new argument list.
*
* @param contents - The positional arguments that make up the primary
* contents of the list. This may be either a plain JavaScript array or an
* immutable [[List]] from the [`immutable`
* package](https://immutable-js.com/).
*
* @param keywords - The keyword arguments attached to this argument list,
* whose names should exclude `$`. This can be either a plain JavaScript
* object with argument names as fields, or an immutable [[OrderedMap]] from
* the [`immutable` package](https://immutable-js.com/)
*
* @param separator - The separator for this list. Defaults to `','`.
*/
constructor(
contents: Value[] | List<Value>,
keywords: Record<string, Value> | OrderedMap<string, Value>,
/** @default ',' */
separator?: ListSeparator
);
/**
* The keyword arguments attached to this argument list.
*
* The argument names don't include `$`.
*
* @returns An immutable [[OrderedMap]] from the [`immutable`
* package](https://immutable-js.com/).
*/
get keywords(): OrderedMap<string, Value>;
}

View File

@ -1,9 +1,29 @@
import {Value} from './index';
/**
* Sass's [`true` value](https://sass-lang.com/documentation/values/booleans).
*
* @category Custom Function
*/
export const sassTrue: SassBoolean;
/**
* Sass's [`false` value](https://sass-lang.com/documentation/values/booleans).
*
* @category Custom Function
*/
export const sassFalse: SassBoolean;
export interface SassBoolean extends Value {
/**
* Sass's [boolean type](https://sass-lang.com/documentation/values/booleans).
*
* @category Custom Function
*/
export class SassBoolean extends Value {
private constructor();
/**
* Whether this value is `true` or `false`.
*/
get value(): boolean;
}

View File

@ -1,6 +1,20 @@
import {Value} from './index';
/**
* Sass's [color type](https://sass-lang.com/documentation/values/colors).
*
* No matter what representation was originally used to create this color, all
* of its channels are accessible.
*
* @category Custom Function
*/
export class SassColor extends Value {
/**
* Creates an RGB color.
*
* @throws `Error` if `red`, `green`, and `blue` aren't between `0` and
* `255`, or if `alpha` isn't between `0` and `1`.
*/
constructor(options: {
red: number;
green: number;
@ -8,6 +22,12 @@ export class SassColor extends Value {
alpha?: number;
});
/**
* Creates an HSL color.
*
* @throws `Error` if `saturation` or `lightness` aren't between `0` and
* `100`, or if `alpha` isn't between `0` and `1`.
*/
constructor(options: {
hue: number;
saturation: number;
@ -15,6 +35,12 @@ export class SassColor extends Value {
alpha?: number;
});
/**
* Creates an HWB color.
*
* @throws `Error` if `whiteness` or `blackness` aren't between `0` and `100`,
* or if `alpha` isn't between `0` and `1`.
*/
constructor(options: {
hue: number;
whiteness: number;
@ -22,24 +48,36 @@ export class SassColor extends Value {
alpha?: number;
});
/** This color's red channel, between `0` and `255`. */
get red(): number;
/** This color's green channel, between `0` and `255`. */
get green(): number;
/** This color's blue channel, between `0` and `255`. */
get blue(): number;
/** This color's hue, between `0` and `360`. */
get hue(): number;
/** This color's saturation, between `0` and `100`. */
get saturation(): number;
/** This color's lightness, between `0` and `100`. */
get lightness(): number;
/** This color's whiteness, between `0` and `100`. */
get whiteness(): number;
/** This color's blackness, between `0` and `100`. */
get blackness(): number;
/** This color's alpha channel, between `0` and `1`. */
get alpha(): number;
/**
* Changes one or more of this color's RGB channels and returns the result.
*/
change(options: {
red?: number;
green?: number;
@ -47,6 +85,9 @@ export class SassColor extends Value {
alpha?: number;
}): SassColor;
/**
* Changes one or more of this color's HSL channels and returns the result.
*/
change(options: {
hue?: number;
saturation?: number;
@ -54,6 +95,9 @@ export class SassColor extends Value {
alpha?: number;
}): SassColor;
/**
* Changes one or more of this color's HWB channels and returns the result.
*/
change(options: {
hue?: number;
whiteness?: number;

View File

@ -1,5 +1,22 @@
import {Value} from './index';
/**
* Sass's [function type](https://sass-lang.com/documentation/values/functions).
*
* **Heads up!** Although first-class Sass functions can be processed by custom
* functions, there's no way to invoke them outside of a Sass stylesheet.
*
* @category Custom Function
*/
export class SassFunction extends Value {
/**
* Creates a new first-class function that can be invoked using
* [`meta.call()`](https://sass-lang.com/documentation/modules/meta#call).
*
* @param signature - The function signature, like you'd write for the
* [`@function rule`](https://sass-lang.com/documentation/at-rules/function).
* @param callback - The callback that's invoked when this function is called,
* just like for a [[CustomFunction]].
*/
constructor(signature: string, callback: (args: Value[]) => Value);
}

View File

@ -17,42 +17,157 @@ export {SassMap} from './map';
export {SassNumber} from './number';
export {SassString} from './string';
/**
* Sass's [`null` value](https://sass-lang.com/documentation/values/null).
*
* @category Custom Function
*/
export const sassNull: Value;
/**
* The abstract base class of Sass's value types.
*
* This is passed to and returned by [[CustomFunction]]s, which are passed into
* the Sass implementation using [[Options.functions]].
*
* @category Custom Function
*/
export abstract class Value implements ValueObject {
protected constructor();
/**
* This value as a list.
*
* All SassScript values can be used as lists. Maps count as lists of pairs,
* and all other values count as single-value lists.
*
* @returns An immutable [[List]] from the [`immutable`
* package](https://immutable-js.com/).
*/
get asList(): List<Value>;
/**
* Whether this value as a list has brackets.
*
* All SassScript values can be used as lists. Maps count as lists of pairs,
* and all other values count as single-value lists.
*/
get hasBrackets(): boolean;
/**
* Whether the value counts as `true` in an `@if` statement and other
* contexts.
*/
get isTruthy(): boolean;
/**
* Returns JavaScript's `null` value if this is [[sassNull]], and returns
* `this` otherwise.
*/
get realNull(): null | Value;
/**
* The separator for this value as a list.
*
* All SassScript values can be used as lists. Maps count as lists of pairs,
* and all other values count as single-value lists.
*/
get separator(): ListSeparator;
/**
* Converts `sassIndex` into a JavaScript-style index into the list returned
* by [[asList]].
*
* Sass indexes are one-based, while JavaScript indexes are zero-based. Sass
* indexes may also be negative in order to index from the end of the list.
*
* @param sassIndex - The Sass-style index into this as a list.
* @param name - The name of the function argument `sassIndex` came from
* (without the `$`) if it came from an argument. Used for error reporting.
* @throws `Error` If `sassIndex` isn't a number, if that number isn't an
* integer, or if that integer isn't a valid index for [[asList]].
*/
sassIndexToListIndex(sassIndex: Value, name?: string): number;
/**
* Returns the value at index `index` in this value as a list, or `undefined`
* if `index` isn't valid for this list.
*
* All SassScript values can be used as lists. Maps count as lists of pairs,
* and all other values count as single-value lists.
*
* This is a shorthand for `this.asList.get(index)`, although it may be more
* efficient in some cases.
*
* **Heads up!** This method uses the same indexing conventions as the
* `immutable` package: unlike Sass the index of the first element is 0, but
* like Sass negative numbers index from the end of the list.
*/
get(index: number): Value | undefined;
/**
* Throws if `this` isn't a [[SassBoolean]].
*
* **Heads up!** Functions should generally use [[isTruthy]] rather than
* requiring a literal boolean.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertBoolean(name?: string): SassBoolean;
/**
* Throws if `this` isn't a [[SassColor]].
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertColor(name?: string): SassColor;
/**
* Throws if `this` isn't a [[SassFunction]].
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertFunction(name?: string): SassFunction;
/**
* Throws if `this` isn't a [[SassMap]].
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertMap(name?: string): SassMap;
/**
* Throws if `this` isn't a [[SassNumber]].
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertNumber(name?: string): SassNumber;
/**
* Throws if `this` isn't a [[SassString]].
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertString(name?: string): SassString;
/**
* Returns `this` as a map if it counts as one (empty lists count as empty
* maps) or `null` if it doesn't.
*/
tryMap(): SassMap | null;
/** Returns whether `this` represents the same value as `other`. */
equals(other: Value): boolean;
/** Returns a hash code that can be used to store `this` in a hash map. */
hashCode(): number;
/** @hidden */
toString(): string;
}

View File

@ -2,19 +2,53 @@ import {List} from 'immutable';
import {Value} from './index';
/**
* Possible separators used by Sass lists. The special separator `null` is only
* used for lists with fewer than two elements, and indicates that the separator
* has not yet been decided for this list.
*
* @category Custom Function
*/
export type ListSeparator = ',' | '/' | ' ' | null;
/**
* Sass's [list type](https://sass-lang.com/documentation/values/lists).
*
* @category Custom Function
*/
export class SassList extends Value {
/**
* Creates a new list.
*
* @param contents - The contents of the list. This may be either a plain
* JavaScript array or an immutable [[List]] from the [`immutable`
* package](https://immutable-js.com/).
*
* @param options.separator - The separator to use between elements of this
* list. Defaults to `','`.
*
* @param options.brackets - Whether the list has square brackets. Defaults to
* `false`.
*/
constructor(
contents: Value[] | List<Value>,
options?: {
/** @default ',' */
separator?: ListSeparator;
brackets?: boolean;
}
);
/**
* Creates an empty list.
*
* @param options.separator - The separator to use between elements of this
* list. Defaults to `','`.
*
* @param options.brackets - Whether the list has square brackets. Defaults to
* `false`.
*/
constructor(options?: {separator?: ListSeparator; brackets?: boolean});
/** @hidden */
get separator(): ListSeparator;
}

View File

@ -3,14 +3,39 @@ import {OrderedMap} from 'immutable';
import {SassList} from './list';
import {Value} from './index';
/**
* Sass's [map type](https://sass-lang.com/documentation/values/maps).
*
* @category Custom Function
*/
export class SassMap extends Value {
/**
* Creates a new map.
*
* @param contents - The contents of the map. This is an immutable
* [[OrderedMap]] from the [`immutable` package](https://immutable-js.com/).
* Defaults to an empty map.
*/
constructor(contents?: OrderedMap<Value, Value>);
/**
* Returns the contents of this map as an immutable [[OrderedMap]] from the
* [`immutable` package](https://immutable-js.com/).
*/
get contents(): OrderedMap<Value, Value>;
/**
* Returns the value associated with `key` in this map, or `undefined` if
* `key` isn't in the map.
*
* This is a shorthand for `this.contents.get(key)`, although it may be more
* efficient in some cases.
*/
get(key: Value): Value | undefined;
/** Inherited from [[Value.get]]. */
get(index: number): SassList | undefined;
/** @hidden */
tryMap(): SassMap;
}

View File

@ -2,7 +2,33 @@ import {List} from 'immutable';
import {Value} from './index';
/**
* Sass's [number type](https://sass-lang.com/documentation/values/numbers).
*
* @category Custom Function
*/
export class SassNumber extends Value {
/**
* Creates a new number with more complex units than just a single numerator.
*
* Upon construction, any compatible numerator and denominator units are
* simplified away according to the conversion factor between them.
*
* @param value - The number's numeric value.
*
* @param unit - If this is a string, it's used as the single numerator unit
* for the number.
*
* @param unit.numeratorUnits - If passed, these are the numerator units to
* use for the number. This may be either a plain JavaScript array or an
* immutable [[List]] from the [`immutable`
* package](https://immutable-js.com/).
*
* @param unit.denominatorUnits - If passed, these are the denominator units
* to use for the number. This may be either a plain JavaScript array or an
* immutable [[List]] from the [`immutable`
* package](https://immutable-js.com/).
*/
constructor(
value: number,
unit?:
@ -13,72 +39,264 @@ export class SassNumber extends Value {
}
);
/** This number's numeric value. */
get value(): number;
/** Whether [[value]] is an integer according to Sass's equality logic. */
get isInt(): boolean;
/**
* If [[value]] is an integer according to [[isInt]], returns [[value]]
* rounded to that integer. If it's not an integer, returns `null`.
*/
get asInt(): number | null;
/**
* This number's numerator units as an immutable [[List]] from the
* [`immutable` package](https://immutable-js.com/).
*/
get numeratorUnits(): List<string>;
/**
* This number's denominator units as an immutable [[List]] from the
* [`immutable` package](https://immutable-js.com/).
*/
get denominatorUnits(): List<string>;
/** Whether this number has any numerator or denominator units. */
get hasUnits(): boolean;
/**
* If [[value]] is an integer according to [[isInt]], returns it rounded to
* that integer. Otherwise, throws an error.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertInt(name?: string): number;
/**
* Returns [[value]] if it's within `min` and `max`. If [[value]] is equal to
* `min` or `max` according to Sass's equality, returns `min` or `max`
* respectively. Otherwise, throws an error.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertInRange(min: number, max: number, name?: string): number;
/**
* If this number has no units, returns it. Otherwise, throws an error.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertNoUnits(name?: string): SassNumber;
/**
* If this number has `unit` as its only unit (and as a numerator), returns
* this number. Otherwise, throws an error.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
assertUnit(unit: string, name?: string): SassNumber;
/** Whether this number has `unit` as its only unit (and as a numerator). */
hasUnit(unit: string): boolean;
/**
* Whether this has exactly one numerator unit, and that unit is compatible
* with `unit`.
*/
compatibleWithUnit(unit: string): boolean;
/**
* Returns a copy of this number, converted to the units represented by
* `newNumerators` and `newDenominators`.
*
* @throws `Error` if this number's units are incompatible with
* `newNumerators` and `newDenominators`; or if this number is unitless and
* either `newNumerators` or `newDenominators` are not empty, or vice-versa.
*
* @param newNumerators - The numerator units to convert this number to. This
* may be either a plain JavaScript array or an immutable [[List]] from the
* [`immutable` package](https://immutable-js.com/).
*
* @param newDenominators - The denominator units to convert this number to.
* This may be either a plain JavaScript array or an immutable [[List]] from
* the [`immutable` package](https://immutable-js.com/).
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
convert(
newNumerators: string[] | List<string>,
newDenominators: string[] | List<string>,
name?: string
): SassNumber;
/**
* Returns a copy of this number, converted to the same units as `other`.
*
* @throws `Error` if this number's units are incompatible with `other`'s
* units, or if either number is unitless but the other is not.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*
* @param otherName - The name of the function argument `other` came from
* (without the `$`) if it came from an argument. Used for error reporting.
*/
convertToMatch(
other: SassNumber,
name?: string,
otherName?: string
): SassNumber;
/**
* Returns [[value]], converted to the units represented by `newNumerators`
* and `newDenominators`.
*
* @throws `Error` if this number's units are incompatible with
* `newNumerators` and `newDenominators`; or if this number is unitless and
* either `newNumerators` or `newDenominators` are not empty, or vice-versa.
*
* @param newNumerators - The numerator units to convert [[value]] to. This
* may be either a plain JavaScript array or an immutable [[List]] from the
* [`immutable` package](https://immutable-js.com/).
*
* @param newDenominators - The denominator units to convert [[value]] to.
* This may be either a plain JavaScript array or an immutable [[List]] from
* the [`immutable` package](https://immutable-js.com/).
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
convertValue(
newNumerators: string[] | List<string>,
newDenominators: string[] | List<string>,
name?: string
): number;
/**
* Returns [[value]], converted to the same units as `other`.
*
* @throws `Error` if this number's units are incompatible with `other`'s
* units, or if either number is unitless but the other is not.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*
* @param otherName - The name of the function argument `other` came from
* (without the `$`) if it came from an argument. Used for error reporting.
*/
convertValueToMatch(
other: SassNumber,
name?: string,
otherName?: string
): number;
/**
* Returns a copy of this number, converted to the units represented by
* `newNumerators` and `newDenominators`.
*
* Unlike [[convert]] this does *not* throw an error if this number is
* unitless and either `newNumerators` or `newDenominators` are not empty, or
* vice-versa. Instead, it treats all unitless numbers as convertible to and
* from all units without changing the value.
*
* @throws `Error` if this number's units are incompatible with
* `newNumerators` and `newDenominators`.
*
* @param newNumerators - The numerator units to convert this number to. This
* may be either a plain JavaScript array or an immutable [[List]] from the
* [`immutable` package](https://immutable-js.com/).
*
* @param newDenominators - The denominator units to convert this number to.
* This may be either a plain JavaScript array or an immutable [[List]] from
* the [`immutable` package](https://immutable-js.com/).
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
coerce(
newNumerators: string[] | List<string>,
newDenominators: string[] | List<string>,
name?: string
): SassNumber;
/**
* Returns a copy of this number, converted to the units represented by
* `newNumerators` and `newDenominators`.
*
* Unlike [[convertToMatch]] this does *not* throw an error if this number is
* unitless and either `newNumerators` or `newDenominators` are not empty, or
* vice-versa. Instead, it treats all unitless numbers as convertible to and
* from all units without changing the value.
*
* @throws `Error` if this number's units are incompatible with `other`'s
* units.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*
* @param otherName - The name of the function argument `other` came from
* (without the `$`) if it came from an argument. Used for error reporting.
*/
coerceToMatch(
other: SassNumber,
name?: string,
otherName?: string
): SassNumber;
/**
* Returns [[value]], converted to the units represented by `newNumerators` and
* `newDenominators`.
*
* Unlike [[convertValue]] this does *not* throw an error if this number is
* unitless and either `newNumerators` or `newDenominators` are not empty, or
* vice-versa. Instead, it treats all unitless numbers as convertible to and
* from all units without changing the value.
*
* @throws `Error` if this number's units are incompatible with
* `newNumerators` and `newDenominators`.
*
* @param newNumerators - The numerator units to convert [[value]] to. This
* may be either a plain JavaScript array or an immutable [[List]] from the
* [`immutable` package](https://immutable-js.com/).
*
* @param newDenominators - The denominator units to convert [[value]] to.
* This may be either a plain JavaScript array or an immutable [[List]] from
* the [`immutable` package](https://immutable-js.com/).
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*/
coerceValue(
newNumerators: string[] | List<string>,
newDenominators: string[] | List<string>,
name?: string
): number;
/**
* Returns [[value]], converted to the units represented by `newNumerators`
* and `newDenominators`.
*
* Unlike [[convertValueToMatch]] this does *not* throw an error if this
* number is unitless and either `newNumerators` or `newDenominators` are not
* empty, or vice-versa. Instead, it treats all unitless numbers as
* convertible to and from all units without changing the value.
*
* @throws `Error` if this number's units are incompatible with `other`'s
* units.
*
* @param name - The name of the function argument `this` came from (without
* the `$`) if it came from an argument. Used for error reporting.
*
* @param otherName - The name of the function argument `other` came from
* (without the `$`) if it came from an argument. Used for error reporting.
*/
coerceValueToMatch(
other: SassNumber,
name?: string,

View File

@ -1,21 +1,84 @@
import {Value} from './index';
/**
* Sass's [string type](https://sass-lang.com/documentation/values/strings).
*
* @category Custom Function
*/
export class SassString extends Value {
/**
* Creates a new string.
*
* @param text - The contents of the string. For quoted strings, this is the
* semantic contentany escape sequences that were been written in the source
* text are resolved to their Unicode values. For unquoted strings, though,
* escape sequences are preserved as literal backslashes.
*
* @param options.quotes - Whether the string is quoted. Defaults to `true`.
*/
constructor(
text: string,
options?: {
/** @default true */
quotes?: boolean;
}
);
/**
* Creates an empty string.
*
* @param options.quotes - Whether the string is quoted. Defaults to `true`.
*/
constructor(options?: {quotes?: boolean});
/**
* The contents of the string.
*
* For quoted strings, this is the semantic contentany escape sequences that
* were been written in the source text are resolved to their Unicode values.
* For unquoted strings, though, escape sequences are preserved as literal
* backslashes.
*
* This difference allows us to distinguish between identifiers with escapes,
* such as `url\u28 http://example.com\u29`, and unquoted strings that contain
* characters that aren't valid in identifiers, such as
* `url(http://example.com)`. Unfortunately, it also means that we don't
* consider `foo` and `f\6F\6F` the same string.
*/
get text(): string;
/** Whether this string has quotes. */
get hasQuotes(): boolean;
/**
* Sass's notion of this string's length.
*
* Sass treats strings as a series of Unicode code points while JavaScript
* treats them as a series of UTF-16 code units. For example, the character
* U+1F60A SMILING FACE WITH SMILING EYES is a single Unicode code point but
* is represented in UTF-16 as two code units (`0xD83D` and `0xDE0A`). So in
* JavaScript, `"n😊b".length` returns `4`, whereas in Sass
* `string.length("n😊b")` returns `3`.
*/
get sassLength(): number;
/**
* Converts `sassIndex` to a JavaScript index into [[text]].
*
* Sass indices are one-based, while JavaScript indices are zero-based. Sass
* indices may also be negative in order to index from the end of the string.
*
* In addition, Sass indices refer to Unicode code points while JavaScript
* string indices refer to UTF-16 code units. For example, the character
* U+1F60A SMILING FACE WITH SMILING EYES is a single Unicode code point but
* is represented in UTF-16 as two code units (`0xD83D` and `0xDE0A`). So in
* JavaScript, `"n😊b".charCodeAt(1)` returns `0xD83D`, whereas in Sass
* `string.slice("n😊b", 1, 1)` returns `"😊"`.
*
* This function converts Sass's code point indices to JavaScript's code unit
* indices. This means it's O(n) in the length of `text`.
*
* @throws `Error` - If `sassIndex` isn't a number, if that number isn't an
* integer, or if that integer isn't a valid index for this string.
*/
sassIndexToStringIndex(sassIndex: Value, name?: string): number;
}

View File

@ -6,7 +6,9 @@ import {Options, StringOptions} from './options';
/** The object returned by the compiler when a Sass compilation succeeds. */
export interface CompileResult {
css: string;
loadedUrls: URL[];
sourceMap?: RawSourceMap;
}

View File

@ -6,6 +6,8 @@ import {SourceSpan} from './logger';
* argument verification errors.
*/
export class Exception extends Error {
private constructor();
/**
* The compiler supplies this error message to the JS runtime. This should
* contain the description of the Sass exception as well as human-friendly
@ -23,7 +25,7 @@ export class Exception extends Error {
*
* > The format can vary from implementation to implementation.
*/
sassMessage: string;
readonly sassMessage: string;
/**
* A human-friendly representation of the loads, function calls, and mixin
@ -31,7 +33,7 @@ export class Exception extends Error {
*
* > The format can vary from implementation to implementation.
*/
sassStack: string;
readonly sassStack: string;
/**
* A span whose `url` is the canonical URL of the stylesheet being parsed or
@ -43,7 +45,7 @@ export class Exception extends Error {
* > that this covers a span of text that clearly indicates the location of
* > the error.
*/
span: SourceSpan;
readonly span: SourceSpan;
/**
* Provides a formatted string with useful information about the error.

View File

@ -45,6 +45,8 @@ export {
Options,
OutputStyle,
StringOptions,
StringOptionsWithImporter,
StringOptionsWithoutImporter,
Syntax,
} from './options';
export {PromiseOr} from './util/promise_or';

View File

@ -121,23 +121,28 @@ export interface Options<sync extends 'sync' | 'async'> {
verbose?: boolean;
}
/** Additional options specific to compiling from a string. */
export type StringOptions<sync extends 'sync' | 'async'> = Options<sync> & {
export interface StringOptionsWithoutImporter<sync extends 'sync' | 'async'>
extends Options<sync> {
/**
* The compiler must parse `source` using this syntax.
*
* @default 'scss'
*/
syntax?: Syntax;
} & (
| {
/** The canonical URL of the entrypoint. */
url?: URL;
}
| {
/** The importer to use to resolve relative imports in the entrypoint. */
importer: Importer<sync> | FileImporter<sync>;
/** The canonical URL of the entrypoint. */
url: URL;
}
);
/** When `importer` isn't passed, this is purely advisory. */
url?: URL;
}
export interface StringOptionsWithImporter<sync extends 'sync' | 'async'>
extends StringOptionsWithoutImporter<sync> {
/** The importer to use to resolve relative imports in the entrypoint. */
importer: Importer<sync> | FileImporter<sync>;
/** The canonical URL of the entrypoint. */
url: URL;
}
export type StringOptions<sync extends 'sync' | 'async'> =
| StringOptionsWithImporter<sync>
| StringOptionsWithoutImporter<sync>;

View File

@ -2,6 +2,6 @@
* A utility type for choosing between synchronous and asynchronous return
* values.
*/
export type PromiseOr<T, sync extends 'sync' | 'async'> = sync extends 'sync'
? T
: T | Promise<T>;
export type PromiseOr<T, sync extends 'sync' | 'async'> = sync extends 'async'
? T | Promise<T>
: T;

View File

@ -7,6 +7,8 @@ export const sassTrue: SassBoolean;
export const sassFalse: SassBoolean;
/** The JS API representation of a Sass boolean. */
export interface SassBoolean extends Value {
export class SassBoolean extends Value {
private constructor();
get value(): boolean;
}

View File

@ -1,4 +1,20 @@
{
"excludePrivate": true,
"excludeProtected": true
"excludeProtected": true,
"categorizeByGroup": false,
"categoryOrder": [
"Compile",
"Options",
"Logger",
"Importer",
"Custom Function",
"Other",
"Legacy",
"Input",
"Output",
"Plugins",
"Messages",
"Source Maps"
]
}