[Containing URL] Update types

This commit is contained in:
Natalie Weizenbaum 2023-06-30 13:36:53 -07:00
parent f61b9165c3
commit 5498410990
2 changed files with 76 additions and 11 deletions

View File

@ -62,6 +62,11 @@ export interface FileImporter<
* This should *only* be used for determining whether or not to load * 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). * [import-only files](https://sass-lang.com/documentation/at-rules/import#import-only-files).
* *
* @param options.containingUrl - The canonical URL of the source file that's
* loading `url`, if it has one. Unlike for {@link Importer.canonicalize},
* this is always available as long as the containing file has a canonical
* URL.
*
* @returns An absolute `file:` URL if this importer recognizes the `url`. * @returns An absolute `file:` URL if this importer recognizes the `url`.
* This may be only partially resolved: the compiler will automatically look * This may be only partially resolved: the compiler will automatically look
* for [partials](https://sass-lang.com/documentation/at-rules/use#partials), * for [partials](https://sass-lang.com/documentation/at-rules/use#partials),
@ -85,7 +90,7 @@ export interface FileImporter<
*/ */
findFileUrl( findFileUrl(
url: string, url: string,
options: {fromImport: boolean} options: {fromImport: boolean, containingUrl?: URL}
): PromiseOr<URL | null, sync>; ): PromiseOr<URL | null, sync>;
/** @hidden */ /** @hidden */
@ -226,6 +231,11 @@ export interface Importer<sync extends 'sync' | 'async' = 'sync' | 'async'> {
* This should *only* be used for determining whether or not to load * 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). * [import-only files](https://sass-lang.com/documentation/at-rules/import#import-only-files).
* *
* @param options.containingUrl - The canonical URL of the source file that's
* loading `url`, if it has one. This is only passed when `url` is either
* relative or an absolute URL whose scheme is declared as non-canonical by
* {@link nonCanonicalScheme}.
*
* @returns An absolute URL if this importer recognizes the `url`, or `null` * @returns An absolute URL if this importer recognizes the `url`, or `null`
* if it doesn't. If this returns `null`, other importers or {@link * if it doesn't. If this returns `null`, other importers or {@link
* Options.loadPaths | load paths} may handle the load. * Options.loadPaths | load paths} may handle the load.
@ -242,7 +252,7 @@ export interface Importer<sync extends 'sync' | 'async' = 'sync' | 'async'> {
*/ */
canonicalize( canonicalize(
url: string, url: string,
options: {fromImport: boolean} options: {fromImport: boolean, containingUrl?: URL}
): PromiseOr<URL | null, sync>; ): PromiseOr<URL | null, sync>;
/** /**
@ -272,6 +282,28 @@ export interface Importer<sync extends 'sync' | 'async' = 'sync' | 'async'> {
/** @hidden */ /** @hidden */
findFileUrl?: never; findFileUrl?: never;
/**
* One or more URL schemes that this importer supports, but will never return
* from {@link canonicalize}. When an absolute URL with one of these schemes
* is passed to {@link canonicalize}, the URL of the stylesheet that contains
* it will be available as well.
*
* This restriction is in place to ensure that canonical URLs are always
* resolved the same way regardless of context, and thus that they're truly
* canonical.
*
* These values must be valid lowercase URL schemes.
*
* @example An plugin for the fictional NetCram bundler might support a
* `netcram:` URL scheme. It would declare `nonCanonicalScheme: "netcram"` so
* that when a user wrote `@use "netcram:colorful"`, it would be able to load
* different versions of the `colorful` library depending where the `@use` was
* located. Its `canonicalize()` function would then return a normal `file:`
* URL as the canonical URL for these files, representing their locations on
* disk.
*/
nonCanonicalScheme?: string | string[];
} }
/** /**

View File

@ -33,14 +33,19 @@ string `string`:
* Let `fromImport` be `true` if the importer is being run for an `@import` and * Let `fromImport` be `true` if the importer is being run for an `@import` and
`false` otherwise. `false` otherwise.
* Let `url` be the result of calling `findFileUrl` with `string` and * Let `containingUrl` be the canonical URL of the [current source file] if it
`fromImport`. If it returns a promise, wait for it to complete and use its has one, or undefined otherwise.
value instead, or rethrow its error if it rejects.
* Let `url` be the result of calling `findFileUrl` with `string`,
`fromImport`, and `containingUrl`. If it returns a promise, wait for it to
complete and use its value instead, or rethrow its error if it rejects.
* If `url` is null, return null. * If `url` is null, return null.
* If `url`'s scheme is not `file`, throw an error. * If `url`'s scheme is not `file`, throw an error.
[current source file]: ../spec.md#current-source-file
* Let `resolved` be the result of [resolving `url`]. * Let `resolved` be the result of [resolving `url`].
[resolving `url`]: ../modules.md#resolving-a-file-url [resolving `url`]: ../modules.md#resolving-a-file-url
@ -65,7 +70,7 @@ export interface FileImporter<
> { > {
findFileUrl( findFileUrl(
url: string, url: string,
options: {fromImport: boolean} options: {fromImport: boolean, containingUrl?: URL}
): PromiseOr<URL | null, sync>; ): PromiseOr<URL | null, sync>;
canonicalize?: never; canonicalize?: never;
@ -80,9 +85,18 @@ string `string`:
* Let `fromImport` be `true` if the importer is being run for an `@import` and * Let `fromImport` be `true` if the importer is being run for an `@import` and
`false` otherwise. `false` otherwise.
* Let `url` be the result of calling `canonicalize` with `url` and `fromImport`. * If `string` is a relative URL, or if it's an absolute URL whose scheme is
If it returns a promise, wait for it to complete and use its value instead, or non-canonical for this importer, let `containingUrl` be the canonical URL of
rethrow its error if it rejects. the [current source file]. Otherwise, or if the current source file has no
canonical URL, let `containingUrl` be undefined.
* Let `url` be the result of calling `canonicalize` with `string`, `fromImport`,
and `containingUrl`. If it returns a promise, wait for it to complete and use
its value instead, or rethrow its error if it rejects.
* If the scheme of `url` is [non-canonical] for this importer, throw an error.
[non-canonical]: #noncanonicalscheme
* If `url` is null, return null. * If `url` is null, return null.
@ -104,13 +118,32 @@ string `string`:
export interface Importer<sync extends 'sync' | 'async' = 'sync' | 'async'> { export interface Importer<sync extends 'sync' | 'async' = 'sync' | 'async'> {
canonicalize( canonicalize(
url: string, url: string,
options: {fromImport: boolean} options: {fromImport: boolean; containingUrl?: URL}
): PromiseOr<URL | null, sync>; ): PromiseOr<URL | null, sync>;
load(canonicalUrl: URL): PromiseOr<ImporterResult | null, sync>; load(canonicalUrl: URL): PromiseOr<ImporterResult | null, sync>;
findFileUrl?: never; findFileUrl?: never;
} ```
#### `nonCanonicalScheme`
The set of URL schemes that are considered *non-canonical* for this importer. If
this is a single string, treat it as a list containing that string.
Before beginning compilation, throw an error if any element of this is empty or
contains a character other than a lowercase ASCII letter, an ASCII numeral,
U+002B (`+`), U+002D (`-`), or U+002E (`.`).
> Uppercase letters are normalized to lowercase in the `URL` constructor, so for
> simplicity and efficiency we only allow lowercase here.
```ts
nonCanonicalScheme?: string | string[];
```
```
} // Importer
``` ```
### `ImporterResult` ### `ImporterResult`