Request for Comments: Neue JS API

Veröffentlicht am 5. August 2021 von Natalie Weizenbaum

Ich freue mich, etwas vorstellen zu können, das schon seit einiger Zeit in Arbeit ist: eine (ein Vorschlag für eine) brandneue JavaScript-API für Sass. Diese API wurde von Grund auf neu konzipiert, basierend auf den Erfahrungen mit der Node Sass API und verschiedenen anderen historischen Sass-APIs in anderen Sprachen im Laufe der Jahre, und sie behebt viele der Mängel der bestehenden API.

Die API hat vier Hauptkomponenten, die ich alle in diesem Beitrag behandeln werde.

Denken Sie beim Weiterlesen daran, dass diese API noch ein Vorschlag ist. Wir möchten von Ihnen, unseren Nutzern, hören, ob sie Ihren Bedürfnissen entspricht und wie wir sie verbessern können, bevor wir sie für eine vollständige Veröffentlichung festlegen. Also machen Sie ruhig Ihren Standpunkt bekannt im Issue Tracker!

Warum eine neue API?Warum eine neue API?  Permalink

Die bestehende JavaScript-API ist in die Jahre gekommen. Sie stammt aus der Zeit vor Dart Sass und wurde ursprünglich für das Paket node-sass entwickelt, das die nun veraltete LibSass-Implementierung umhüllte. (Deshalb nennen wir sie die "Node Sass API"!) Sie wuchs organisch und oft unordentlich mit LibSass zusammen und endete mit einigen unbeholfenen Legacy-Verhaltensweisen. Viele dieser Verhaltensweisen sind eher ein Problem für die Implementierung als sonst etwas, aber einige wenige machten das Leben ziemlich schwierig.

  • Die Importer-API war um Dateipfade und nicht um URLs herum aufgebaut und war eng mit dem physischen Dateisystem verknüpft. Dies machte es unmöglich, *alle* dateibasierten Ladevorgänge zu überschreiben und ein vollständig virtuelles Dateisystem bereitzustellen, und führte dazu, dass benutzerdefinierte Node-Importer schlecht mit dem neuen Modulsystem interagierten.

  • Die Funktions-API war um mutierbare Wertobjekte aufgebaut, was im Widerspruch zur unveränderlichen Natur von Sass steht. Sie bot auch keine Hilfsmethoden (wie das Nachschlagen eines Schlüssels in einer Map), um die Implementierung idiomatischer benutzerdefinierter Funktionen zu erleichtern, und bot keinen Zugriff auf entscheidende Informationen über Werte, wie z. B. ob Strings zitiert waren.

  • Alle asynchronen Funktionen basierten auf Callbacks und nicht auf Promises.

Die neue API adressiert diese und weitere Probleme mit einer modernen, idiomatischen API, die die Arbeit mit Sass aus JS zum Kinderspiel macht.

KompilierungKompilierung Permalink

Das Herzstück der API bilden vier Funktionen, die die eigentliche Sass-Kompilierung durchführen, zwei synchron und zwei asynchron. Sie sind hier in TypeScript-Syntax dargestellt, um genau zu verdeutlichen, was sie empfangen und zurückgeben, aber Sie können sie jederzeit aus reinem JS aufrufen.

function compile(
  path: string,
  options?: Options<'sync'>
): CompileResult;

function compileString(
  source: string,
  options?: StringOptions<'sync'>
): CompileResult;

function compileAsync(
  path: string,
  options?: Options<'async'>
): Promise<CompileResult>;

function compileStringAsync(
  source: string,
  options?: StringOptions<'async'>
): Promise<CompileResult>;

Die Funktionen compile() und compileAsync() laden eine Sass-Datei von einem Pfad auf der Festplatte, während compileString() und compileStringAsync() Sass-Quellcode kompilieren, der als String übergeben wird. Alle diese empfangen die folgenden Optionen:

  • alertAscii: Ob Fehler und Warnungen nur ASCII-Zeichen verwenden sollen (im Gegensatz zu z. B. Unicode-Zeichen für Rahmenzeichnungen ).
  • alertColor: Ob Fehler und Warnungen Terminalfarben verwenden sollen .
  • loadPaths: Eine Liste von Dateipfaden, die zum Nachschlagen zu ladender Dateien verwendet werden, ähnlich wie includePaths in der alten API.
  • importers: Eine Liste von benutzerdefinierten Importern zum Laden von Sass-Quelldateien .
  • functions: Ein Objekt, dessen Schlüssel Sass-Funktionssignaturen sind und dessen Werte benutzerdefinierte Funktionen sind.
  • quietDeps: Ob Depikationswarnungen in Abhängigkeiten stummgeschaltet werden sollen .
  • logger: Der benutzerdefinierte Logger, der zur Ausgabe von Warnungen und Debug-Nachrichten verwendet wird .
  • sourceMap: Ob während der Kompilierung eine Source Map generiert werden soll .
  • style: Der Ausgabestil: 'compressed' oder 'expanded'.
  • verbose: Ob jede aufgetretene Depikationswarnung ausgegeben werden soll .

Die Funktionen compileString() und compileStringAsync() empfangen einige zusätzliche Optionen:

  • syntax: Die Syntax der Datei: 'scss' (Standard), 'indented' oder 'css'.
  • url: Die kanonische URL der Datei.
  • importer: Der benutzerdefinierte Importer, der als Quelle der Datei behandelt werden soll. Wenn dieser übergeben wird, wird dieser Importer verwendet, um relative Ladevorgänge aus diesem Stylesheet aufzulösen.

Alle diese Funktionen geben ein Objekt mit den folgenden Feldern zurück:

  • css: Das kompilierte CSS als String.
  • loadedUrls: Alle während der Kompilierung geladenen URLs, in keiner bestimmten Reihenfolge.
  • sourceMap: Die Source Map für die Datei, wenn sourceMap: true übergeben wurde, als dekodiertes Objekt.

Wie bei der Node Sass API werden die synchronen Funktionen erheblich schneller sein als ihre asynchronen Gegenstücke. Leider wird die neue API die Option fibers zur Beschleunigung der asynchronen Kompilierung nicht unterstützen, da das Paket fibers eingestellt wurde.

LoggerLogger Permalink

Die Logger-API bietet Ihnen eine feinere Kontrolle darüber, wie und wann Warnungen und Debug-Nachrichten ausgegeben werden. Im Gegensatz zu anderen Aspekten dieses Vorschlags wird eine logger-Option auch der *alten* API hinzugefügt, damit Sie Ihre Nachrichten dort steuern können, ohne sofort auf die neue API aktualisieren zu müssen .

Ein Logger implementiert die folgende Schnittstelle:

interface Logger {
  warn?(
    message: string,
    options: {
      deprecation: boolean;
      span?: SourceSpan;
      stack?: string;
    }
  ): void;

  debug?(
    message: string,
    options: {span: SourceSpan}
  ): void;
}

Die Funktion warn behandelt Warnungen, einschließlich Warnungen sowohl vom Compiler selbst als auch von @warn-Regeln. Sie wird übergeben:

  • Die Warnmeldung
  • Ein Flag, das angibt, ob es sich speziell um eine Depikationswarnung handelt .
  • Ein Bereich, der angibt, wo die Warnung lokalisiert wurde, wenn sie von einem bestimmten Ort stammt.
  • Der Sass-Stack-Trace an der Stelle, an der die Warnung aufgetreten ist, wenn sie während der Ausführung aufgetreten ist.

Die Funktion debug behandelt nur @debug-Regeln und erhält lediglich die Nachricht und den Bereich der Regel übergeben. Weitere Informationen zum Typ SourceSpan finden Sie in dem Logger-Vorschlag .

Sass bietet auch einen integrierten Logger, Logger.silent, der niemals Nachrichten ausgibt. Dies ermöglicht es Ihnen, Sass einfach im "stummgeschalteten Modus" auszuführen, in dem niemals Warnungen sichtbar gemacht werden.

ImporterImporter Permalink

Anstatt Importer als Single-Function-Callbacks zu modellieren, modelliert die neue API sie als Objekte, die zwei Methoden bereitstellen: eine, die eine URL *kanonisiert*, und eine, die eine kanonisierte URL *lädt*.

// Importers for compileAsync() and compileStringAsync() are the same, except
// they may return Promises as well.
interface Importer {
  canonicalize(
    url: string,
    options: {fromImport: boolean}
  ): URL | null;

  load(canonicalUrl: URL): ImporterResult | null;
}

Beachten Sie, dass selbst Stylesheets, die direkt aus dem Dateisystem über compile() oder loadPaths geladen werden, so behandelt werden, als würden sie von einem Importer geladen. Dieser integrierte Dateisystem-Importer kanonisiert alle Pfade zu file:-URLs und lädt diese URLs aus dem physischen Dateisystem.

KanonisierungKanonisierung Permalink

Der erste Schritt bestimmt die kanonische URL für ein Stylesheet. Jedes Stylesheet hat genau eine kanonische URL, die wiederum auf genau ein Stylesheet verweist. Die kanonische URL muss absolut sein, einschließlich eines Schemas, aber die genaue Struktur liegt im Ermessen des Importers. In den meisten Fällen existiert das betreffende Stylesheet auf der Festplatte und der Importer gibt einfach eine file:- URL dafür zurück .

Die Methode canonicalize() nimmt eine URL-Zeichenkette entgegen, die entweder relativ oder absolut sein kann. Wenn der Importer diese URL erkennt, gibt er eine entsprechende absolute URL (einschließlich eines Schemas) zurück. Dies ist die *kanonische URL* für das betreffende Stylesheet. Obwohl die Eingabe- URL eine Dateierweiterung oder einen führenden Unterstrich weglassen kann, muss die kanonische URL vollständig aufgelöst sein.

Für ein Stylesheet, das aus dem Dateisystem geladen wird, ist die kanonische URL die absolute file:- URL der physischen Datei auf der Festplatte. Wenn es im Speicher generiert wird, sollte der Importer ein benutzerdefiniertes URL-Schema wählen, um zu garantieren, dass seine kanonischen URLs nicht mit denen eines anderen Importers kollidieren.

Wenn Sie beispielsweise Sass-Dateien aus einer Datenbank laden, könnten Sie das Schema db: verwenden. Die kanonische URL für ein Stylesheet, das mit dem Schlüssel styles in der Datenbank verbunden ist, könnte db:styles lauten.

Diese Funktion nimmt auch eine Option fromImport entgegen, die angibt, ob der Importer von einer @import-Regel aus aufgerufen wird (im Gegensatz zu @use, @forward oder meta.load-css()).

Eine kanonische URL für jedes Stylesheet zu haben, ermöglicht es Sass sicherzustellen, dass dasselbe Stylesheet im neuen Modulsystem nicht mehrmals geladen wird .

Kanonisierung relativer LadevorgängeKanonisierung relativer Ladevorgänge  Permalink

Wenn ein Stylesheet versucht, eine relative URL zu laden, z. B. @use "variables", ist es aus dem Dokument selbst nicht klar, ob dies auf eine Datei verweist, die relativ zum Stylesheet existiert, oder auf einen anderen Importer oder Pfad. Hier ist, wie die Importer-API diese Mehrdeutigkeit auflöst:

  • Zuerst wird die relative URL relativ zur kanonischen URL des Stylesheets aufgelöst, das @use (oder @forward oder @import) enthielt. Wenn die kanonische URL beispielsweise file:///path/to/my/_styles.scss lautet, dann ist die aufgelöste URL file:///path/to/my/variables.

  • Diese URL wird dann an die canonicalize()-Methode des Importers übergeben, der das alte Stylesheet geladen hat. (Das bedeutet, dass es wichtig ist, dass Ihre Importer absolute URLs unterstützen!) Wenn der Importer sie erkennt, gibt er den kanonischen Wert zurück, der dann an die load()-Methode dieses Importers übergeben wird; andernfalls gibt er null zurück.

  • Wenn der Importer des alten Stylesheets die URL nicht erkannte, wird sie an alle canonicalize-Funktionen der importers in der Reihenfolge ihrer Erscheinung in options übergeben und dann in allen loadPaths gesucht. Wenn keiner davon sie erkennt, schlägt der Ladevorgang fehl.

Es ist wichtig, dass lokale relative Pfade Vorrang vor anderen Importern oder Load Paths haben, da Ihre lokalen Stylesheets sonst unerwartet durch eine Abhängigkeit, die eine Datei mit einem widersprüchlichen Namen hinzufügt, unterbrochen werden könnten.

LadenLaden Permalink

Der zweite Schritt lädt tatsächlich den Text des Stylesheets. Die Methode load() nimmt eine kanonische URL entgegen, die von canonicalize() zurückgegeben wurde, und gibt den Inhalt des Stylesheets unter dieser URL zurück. Dies wird pro Kompilierung nur einmal für jede kanonische URL aufgerufen. Zukünftige Ladevorgänge derselben URL verwenden entweder das vorhandene Modul (für @use und @forward) oder den Parse-Baum (für @import) wieder.

Die Methode load() gibt ein Objekt mit den folgenden Feldern zurück:

  • css: Der Text des geladenen Stylesheets.
  • syntax: Die Syntax der Datei: 'scss', 'indented' oder 'css'.
  • sourceMapUrl: Eine optionale, im Browser zugängliche URL, die in Source Maps eingefügt wird, wenn auf diese Datei verwiesen wird.

FileImporterFileImporter Permalink

Dieser Vorschlag fügt auch einen speziellen Typ von Importer hinzu, der als FileImporter bekannt ist. Dieser Importer vereinfacht den üblichen Fall, Ladevorgänge an einen Ort im physischen Dateisystem umzuleiten. Er erfordert nicht, dass der Aufrufer load() implementiert, da dies für Dateien auf der Festplatte immer dasselbe sein wird .

interface FileImporter {
  findFileUrl(
    url: string,
    options: {fromImport: boolean}
  ): FileImporterResult | null;
}

Die Methode findFileUrl() nimmt eine relative URL entgegen und gibt ein Objekt mit den folgenden Feldern zurück:

  • url: Die absolute file:- URL der zu ladenden Datei. Diese URL muss nicht vollständig kanonisiert sein: Der Sass-Compiler kümmert sich um das Auflösen von Partials, Dateierweiterungen, Indexdateien und so weiter.
  • sourceMapUrl: Eine optionale, im Browser zugängliche URL, die in Source Maps eingefügt wird, wenn auf diese Datei verwiesen wird.

FunktionenFunktionen Permalink

Der Funktionstyp der neuen API ist dem der alten API sehr ähnlich.

type CustomFunctionCallback = (args: Value[]) => Value;

Die einzigen Unterschiede sind:

  • Asynchrone Funktionen geben ein Promise<Value> zurück, anstatt einen Callback aufzurufen.
  • Die Werttypen selbst sind unterschiedlich.

Der zweite Punkt ist jedoch ziemlich bedeutsam! Die neuen Werttypen sind im Vergleich zu den alten Versionen viel ausgefeilter. Beginnen wir mit der Elternklasse .

abstract class Value {
  /**
   * Returns the values of `this` when interpreted as a list.
   *
   * - For a list, this returns its elements.
   * - For a map, this returns each of its key/value pairs as a `SassList`.
   * - For any other value, this returns a list that contains only that value.
   */
  get asList(): List<Value>;

  /** Whether `this` is a bracketed Sass list. */
  get hasBrackets(): boolean;

  /** Whether `this` is truthy (any value other than `null` or `false`). */
  get isTruthy(): boolean;

  /** Returns JS's null if this is `sassNull`, or `this` otherwise. */
  get realNull(): null | Value;

  /** If `this` is a list, return its separator. Otherwise, return `null`. */
  get separator(): ListSeparator;

  /**
   * Converts the Sass index `sassIndex` to a JS index into the array returned
   * by `asList`.
   *
   * Sass indices start counting at 1, and may be negative in order to index
   * from the end of the list.
   */
  sassIndexToListIndex(sassIndex: Value): number;

  /**
   * Returns `this` if it's a `SassBoolean`, and throws an error otherwise.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of a parameter passed to the custom function (without the `$`).
   */
  assertBoolean(name?: string): SassBoolean;

  /**
   * Returns `this` if it's a `SassColor`, and throws an error otherwise.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of a parameter passed to the custom function (without the `$`).
   */
  assertColor(name?: string): SassColor;

  /**
   * Returns `this` if it's a `SassFunction`, and throws an error otherwise.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of the parameter passed to the custom function (without the `$`).
   */
  assertFunction(name?: string): SassFunction;

  /**
   * Returns `this` if it's a `SassMap` (or converts it to a `SassMap` if it's
   * an empty list), and throws an error otherwise.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of the parameter passed to the custom function (without the `$`).
   */
  assertMap(name?: string): SassMap;

  /**
   * Returns `this` if it's a `SassNumber`, and throws an error otherwise.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of a parameter passed to the custom function (without the `$`).
   */
  assertNumber(name?: string): SassNumber;

  /**
   * Returns `this` if it's a `SassString`, and throws an error otherwise.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of a parameter passed to the custom function (without the `$`).
   */
  assertString(name?: string): SassString;

  /**
   * Returns the value of `this` if it can be interpreted as a map.
   *
   * - If this is a map, returns its contents.
   * - If this is an empty list, returns an empty map.
   * - Otherwise, returns `null`.
   */
  tryMap(): OrderedMap<Value, Value> | null;

  /** Returns whether `this == other` in SassScript. */
  equals(other: Value): boolean;
}

Hier gibt es ein paar wichtige Dinge zu beachten :

  • Da CSS keine starke syntaktische Unterscheidung zwischen einem einzelnen Element und einer Liste mit einem Element hat, kann jeder Sass-Wert als Liste behandelt werden. Value erleichtert die Befolgung dieser Konvention, indem die Getter asList(), hasBrackets() und separator() für jeden Value verfügbar gemacht werden.

  • Die hier zurückgegebene Liste und die von asMap() zurückgegebene Map sind unveränderliche Typen aus dem Paket immutable. Dies spiegelt die eingebaute Unveränderlichkeit aller Sass-Typen wider. Obwohl diese Werte nicht direkt geändert werden können, erleichtert und beschleunigt ihre API die Erstellung neuer Werte mit angewendeten Änderungen.

  • Die Listenindizierungs-Konventionen von Sass unterscheiden sich von denen von JavaScript. Die Funktion sassIndexToListIndex() erleichtert die Konvertierung von Sass-Indizes in JS- Indizes.

  • In Sass kann jeder Wert in einem booleschen Kontext verwendet werden, wobei false und null als "falsche" Werte zählen. Der Getter isTruthy erleichtert die Befolgung dieser Konvention.

  • Die Funktionen assert*() erleichtern die Sicherstellung, dass die erwarteten Argumente übergeben werden, und das Auslösen eines idiomatischen Fehlers, wenn dies nicht der Fall ist. Sie sind besonders nützlich für TypeScript-Benutzer, da sie den Typ des Value automatisch einschränken.

Die meisten Sass-Werte haben eigene Unterklassen, aber es gibt drei Singleton-Werte, die einfach als Konstanten verfügbar sind: sassTrue, sassFalse und sassNull repräsentieren die Sass-Werte true, false und null .

FarbenFarben Permalink

Die SassColor-Klasse der neuen API bietet Zugriff auf Farben im RGB-, HSL- und HWB-Format. Wie bei den integrierten Sass-Farbfunktionen kann jedes Attribut auf jeder Farbe abgerufen werden, unabhängig davon, wie sie ursprünglich erstellt wurde.

class SassColor extends Value {
  /** Creates an RGB color. */
  static rgb(
    red: number,
    green: number,
    blue: number,
    alpha?: number
  ): SassColor;

  /** Creates an HSL color. */
  static hsl(
    hue: number,
    saturation: number,
    lightness: number,
    alpha?: number
  ): SassColor;

  /** Creates an HWB color. */
  static hwb(
    hue: number,
    whiteness: number,
    blackness: number,
    alpha?: number
  ): SassColor;

  /** The color's red channel. */
  get red(): number;

  /** The color's green channel. */
  get green(): number;

  /** The color's blue channel. */
  get blue(): number;

  /** The color's hue. */
  get hue(): number;

  /** The color's saturation. */
  get saturation(): number;

  /** The color's lightness. */
  get lightness(): number;

  /** The color's whiteness. */
  get whiteness(): number;

  /** The color's blackeness. */
  get blackness(): number;

  /** The color's alpha channel. */
  get alpha(): number;

  /**
   * Returns a copy of `this` with the RGB channels updated to match `options`.
   */
  changeRgb(options: {
    red?: number;
    green?: number;
    blue?: number;
    alpha?: number;
  }): SassColor;

  /**
   * Returns a copy of `this` with the HSL values updated to match `options`.
   */
  changeHsl(options: {
    hue?: number;
    saturation?: number;
    lightness?: number;
    alpha?: number;
  }): SassColor;

  /**
   * Returns a copy of `this` with the HWB values updated to match `options`.
   */
  changeHwb(options: {
    hue?: number;
    whiteness?: number;
    blackness?: number;
    alpha?: number;
  }): SassColor;

  /** Returns a copy of `this` with `alpha` as its alpha channel. */
  changeAlpha(alpha: number): SassColor;
}

ZahlenZahlen Permalink

Die SassNumber-Klasse speichert ihre Zähler- und Nenner-Einheiten als Arrays anstelle von Strings. Darüber hinaus bietet sie Methoden zur Überprüfung, ob sie bestimmte Einheiten hat (assertNoUnits(), assertUnit()) und zur Konvertierung in bestimmte Einheiten (convert(), convertToMatch(), convertValue(), convertValueToMatch(), coerce(), coerceValue(), coerceValueToMatch()).

Die numerische Logik von Sass unterscheidet sich auch subtil von der von JS, da Sass Zahlen, die sich um weniger als die 10. Dezimalstelle unterscheiden, als identisch betrachtet. Diese API bietet eine Reihe von Methoden, die bei der Konvertierung zwischen dieser und der numerischen Logik von JavaScript helfen.

class SassNumber extends Value {
  /** Creates a Sass number with no units or a single numerator unit. */
  constructor(value: number, unit?: string);

  /** Creates a Sass number with multiple numerator and/or denominator units. */
  static withUnits(
    value: number,
    options?: {
      numeratorUnits?: string[] | List<string>;
      denominatorUnits?: string[] | List<string>;
    }
  ): SassNumber;

  /** This number's value. */
  get value(): number;

  /**
   * Whether `value` is an integer according to Sass's numeric logic.
   *
   * The integer value can be accessed using `asInt`.
   */
  get isInt(): boolean;

  /**
   * If `value` is an integer according to Sass's numeric logic, returns the
   * corresponding JS integer, or `null` if `value` isn't an integer.
   */
  get asInt(): number | null;

  /** This number's numerator units. */
  get numeratorUnits(): List<string>;

  /** This number's denominator units. */
  get denominatorUnits(): List<string>;

  /** Whether `this` has numerator or denominator units. */
  get hasUnits(): boolean;

  /**
   * If `value` is an integer according to Sass's numeric logic, returns the
   * corresponding JS integer, or throws an error if `value` isn't an integer.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of the parameter passed to the custom function (without the `$`).
   */
  assertInt(name?: string): number;

  /**
   * If `value` is between `min` and `max` according to Sass's numeric logic,
   * returns it clamped to that range. Otherwise, throws an error.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of the parameter passed to the custom function (without the `$`).
   */
  assertInRange(min: number, max: number, name?: string): number;

  /**
   * Returns `this` if it has no units. Otherwise, throws an error.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of a parameter passed to the custom function (without the `$`).
   */
  assertNoUnits(name?: string): SassNumber;

  /**
   * Returns `this` if it has `unit` as its single (numerator) unit. Otherwise,
   * throws an error.
   *
   * The `name` parameter is used for error reporting. It should match the name
   * of a parameter passed to the custom function (without the `$`).
   */
  assertUnit(name?: stringunit: string): SassNumber;

  /** Returns whether `this` has the single numerator unit `unit`. */
  hasUnit(unit: string): boolean;

  /** Returns whether this number's units are compatible with `unit`. */
  compatibleWithUnit(unit: string): boolean;

  /**
   * If this number's units are compatible with `newNumerators` and
   * `newDenominators`, returns a new number with those units that's equal to
   * `this`. Otherwise, throws an error.
   *
   * Note that unitless numbers are only compatible with other unitless numbers.
   */
  convert(
    newNumerators: string[] | List<string>,
    newDenominators: string[] | List<string>
  ): SassNumber;

  /**
   * If this number's units are compatible with `other`'s, returns a new number
   * with `other`'s units that's equal to `this`. Otherwise, throws an error.
   *
   * Note that unitless numbers are only compatible with other unitless numbers.
   */
  convertToMatch(other: SassNumber): SassNumber;

  /** Equivalent to `convert(newNumerators, newDenominators).value`. */
  convertValue(
    newNumerators: string[] | List<string>,
    newDenominators: string[] | List<string>
  ): number;

  /** Equivalent to `convertToMatch(other).value`. */
  convertValueToMatch(other: SassNumber): number;

  /**
   * Like `convert()`, but if `this` is unitless returns a copy of it with the
   * same value and the given units.
   */
  coerce(
    newNumerators: string[] | List<string>,
    newDenominators: string[] | List<string>
  ): SassNumber;

  /**
   * Like `convertToMatch()`, but if `this` is unitless returns a copy of it
   * with the same value and `other`'s units.
   */
  coerceToMatch(other: SassNumber): SassNumber;

  /** Equivalent to `coerce(newNumerators, newDenominators).value`. */
  coerceValue(
    newNumerators: string[] | List<string>,
    newDenominators: string[] | List<string>
  ): number;

  /** Equivalent to `coerceToMatch(other).value`. */
  coerceValueToMatch(other: SassNumber): number;
}

StringsStrings Permalink

Die SassString-Klasse bietet Zugriff auf Informationen darüber, ob der String zitiert ist oder nicht. Wie bei Listen unterscheidet sich die JS-Vorstellung von Indizes von der von Sass, daher bietet sie auch die Methode sassIndexToStringIndex(), um einen JS-Index in einen Sass- Index zu konvertieren.

class SassString extends Value {
  /** Creates a string with the given `text`. */
  constructor(
    text: string,
    options?: {
      /** @default true */
      quotes: boolean;
    }
  );

  /** Creates an empty string`. */
  static empty(options?: {
    /** @default true */
    quotes: boolean;
  }): SassString;

  /** The contents of `this`. */
  get text(): string;

  /** Whether `this` has quotes. */
  get hasQuotes(): boolean;

  /** The number of Unicode code points in `text`. */
  get sassLength(): number;

  /**
   * Converts the Sass index `sassIndex` to a JS index into `text`.
   *
   * Sass indices start counting at 1, and may be negative in order to index
   * from the end of the list. In addition, Sass indexes strings by Unicode code
   * point, while JS indexes them by UTF-16 code unit.
   */
  sassIndexToStringIndex(sassIndex: Value): number;
}

ListenListen Permalink

Wie oben erwähnt, befinden sich die meisten Listenfunktionen auf der Oberklasse Value, um die Befolgung der Sass-Konvention, alle Werte als Listen zu behandeln, zu erleichtern. Die Klasse SassList kann jedoch immer noch konstruiert werden, um neue Listen zu erstellen.

class SassList extends Value {
  /** Creates a Sass list with the given `contents`. */
  constructor(
    contents: Value[] | List<Value>,
    options?: {
      /** @default ',' */
      separator?: ListSeparator;
      /** @default false */
      brackets?: boolean;
    }
  );

  /** Creates an empty Sass list. */
  static empty(options?: {
    /** @default null */
    separator?: ListSeparator;
    /** @default false */
    brackets?: boolean;
  }): SassList;
}

MapsMaps Permalink

Die SassMap-Klasse gibt einfach ihre Inhalte als OrderedMap aus dem Paket immutable aus.

class SassMap extends Value {
  /** Creates a Sass map with the given `contents`. */
  constructor(contents: OrderedMap<Value, Value>);

  /** Creates an empty Sass map. */
  static empty(): SassMap;

  /** Returns this map's contents. */
  get contents(): OrderedMap<Value, Value>;
}

FunktionenFunktionen Permalink

Die Klasse SassFunction ist ziemlich restriktiv: Sie erlaubt nur die Erstellung einer neuen First-Class-Funktion mit einem synchronen Callback. Diese Funktionen können nicht von benutzerdefinierten Funktionen aufgerufen werden – aber sie bieten immer noch mehr Leistung als die alte API!

class SassFunction extends Value {
  /**
   * Creates a Sass function value with the given `signature` that calls
   * `callback` when it's invoked.
   */
  constructor(
    signature: string,
    callback: CustomFunctionCallback
  );
}

Weitere InformationenWeitere Informationen Permalink

Wenn Sie mehr über diese Vorschläge erfahren und ihre aktuellsten Formen sehen möchten, sind sie auf GitHub vollständig einsehbar :

Wir freuen uns auf Feedback, also lassen Sie uns wissen, was Sie denken! Die betreffenden Vorschläge werden mindestens einen Monat nach der Veröffentlichung dieses Blogbeitrags offen sein, und möglicherweise länger, je nachdem, wie lebhaft die Diskussion darum ist.