accepted/deprecations-api.md
This section is non-normative.
We recently added support to Dart Sass that allowed users to opt in to treating deprecation warnings as errors (on a per-deprecation basis), as well as opting in early to certain future deprecations. This is currently supported on the command line and via the Dart API, but we'd like to extend this support to the JS API as well.
We would also like to add support for silencing a particular deprecation's
warnings, primarily to enable a gentler process for deprecating @import.
This section is non-normative.
This proposal adds a new Deprecation interface and Version class to the
JS API, three new optional properties on Options (fatalDeprecations,
silenceDeprecations, and futureDeprecations), a new parameter on
Logger.warn (options.deprecationType) two type aliases (DeprecationOrId
and DeprecationStatus) and a new object deprecations that contains the
various Deprecation objects.
All deprecations are specified in deprecations, and any new deprecations
added in the future (even those specific to a particular implementation)
should update the specification accordingly. Deprecations should never be
removed from the specification; when the behavior being deprecated is removed
(i.e. there's a major version release), the deprecation status should be
changed to obsolete, but remain in the specification.
Every Deprecation has a unique id, one of four status values, and
(optionally) a human-readable description. Depending on the status, each
deprecation may also have a deprecatedIn version and an obsoleteIn
version that specify the compiler versions the deprecation became active
and became obsolete in, respectively.
Deprecation InterfaceOne alternative to specifying a full Deprecation interface is to just have
the relevant APIs take in string IDs. We considered this, but concluded that
each deprecation has additional metadata that users of the API may wish to
access (for example, a bundler may wish to surface the description and
deprecatedIn version to its users).
We chose to make the list of deprecations part of the specification itself, as this ensures that the language-wide deprecations are consistent across implementations. However, if an implementation wishes to add a deprecation that applies only to itself, it may still do so.
Additionally, while a deprecation's status is part of the specification, we
chose to leave the deprecatedIn and obsoleteIn versions of each
deprecation out of the specification. As the two current implementers of this
API are both based on Dart Sass, these versions are currently consistent
across implementations in practice, potential future implementers should not
need to be tied to Dart Sass's versioning.
Whenever potentially invalid sets of deprecations are passed to any of the options, we choose to emit warnings rather than errors, as the status of each deprecation can change over time, and users may share a configuration when compiling across multiple implementations/versions whose dependency statuses may not be in sync.
The situations we chose to warn for are:
an invalid string ID.
This is disallowed by the API's types, but may still occur at runtime, and should be warned for accordingly.
a future deprecation is passed to fatalDeprecations but not
futureDeprecations.
In this scenario, the future deprecation will still be treated as fatal, but we want to warn users to prevent situations where a user tries to make every deprecation fatal and ends up including future ones too.
an obsolete deprecation is passed to fatalDeprecations.
If a deprecation is obsolete, that means the breaking change has already happened, so making it fatal is a no-op.
passing anything other than an active deprecation to silenceDeprecations.
This is particularly important for obsolete deprecations, since otherwise
users may not be aware of a subtle breaking change for which they were
previously silencing warnings. We also warn for passing
Deprecation.userAuthored, since there's no way to distinguish between
different deprecations from user-authored code, so silencing them as a
group is inadvisable. Passing a future deprecation here is either a no-op,
or cancels out passing it to futureDeprecations, so we warn for that as
well.
passing a non-future deprecation to futureDeprecations.
This is a no-op, so we should warn users so they can clean up their configuration.
import {SourceSpan} from '../spec/js-api';
Optionsdeclare module '../spec/js-api' {
interface Options<sync extends 'sync' | 'async'> {
fatalDeprecationsA set of deprecations to treat as fatal.
If a deprecation warning of any provided type is encountered during compilation, the compiler must error instead.
The compiler should convert any string passed here to a Deprecation by
indexing deprecations. If an invalid deprecation ID is passed here, the
compiler must emit a warning. If a version is passed here, it should be treated
equivalently to passing all active deprecations whose deprecatedIn version is
less than or equal to it.
The compiler must emit a warning if a future deprecation that's not also
included in futureDeprecations or any obsolete deprecation is included here.
If a deprecation is passed both here and to silenceDeprecations, a warning
must be emitted, but making the deprecation fatal must take precedence.
fatalDeprecations?: (DeprecationOrId | Version)[];
silenceDeprecationsA set of active deprecations to ignore.
If a deprecation warning of any provided type is encountered during compilation, the compiler must ignore it.
The compiler should convert any string passed here to a Deprecation by
indexing Deprecations. If an invalid deprecation ID is passed here, the
compiler must emit a warning.
The compiler must emit a warning if any non-active deprecation is included here.
If a future deprecation is included both here and in futureDeprecations, then
silencing it takes precedence.
silenceDeprecations?: DeprecationOrId[];
futureDeprecationsA set of future deprecations to opt into early.
For each future deprecation provided here, the compiler must treat that
deprecation as if it is active, emitting warnings as necessary (subject to
fatalDeprecations and silenceDeprecations).
The compiler should convert any string passed here to a Deprecation by
indexing Deprecations. If an invalid deprecation ID is passed here, the
compiler must emit a warning.
The compiler must emit a warning if a non-future deprecation is included here.
futureDeprecations?: DeprecationOrId[];
} // Options
Loggerinterface Logger {
warnUpdate the third sub-bullet of bullet two to read:
If this warning is caused by behavior that used to be allowed but will be
disallowed in the future, set options.deprecation to true and set
options.deprecationType to the relevant Deprecation. Otherwise, set
options.deprecation to false and leave options.deprecationType undefined.
warn?(
message: string,
options: {
deprecation: boolean;
deprecationType?: Deprecation;
span?: SourceSpan;
stack?: string;
}
): void;
} // Logger
} // module
Deprecationsinterface Deprecations {
call-stringDeprecation for passing a string to call instead of get-function.
'call-string': Deprecation<'call-string'>;
elseifDeprecation for @elseif.
elseif: Deprecation<'elseif'>;
moz-documentDeprecation for parsing @-moz-document.
'moz-document': Deprecation<'moz-document'>;
relative-canonicalDeprecation for importers using relative canonical URLs.
'relative-canonical': Deprecation<'relative-canonical'>;
new-globalDeprecation for declaring new variables with !global.
'new-global': Deprecation<'new-global'>;
color-module-compatDeprecation for certain functions in the color module matching the behavior of their global counterparts for compatibility reasons.
'color-module-compat': Deprecation<'color-module-compat'>;
slash-divDeprecation for treating / as division.
Update the proposal for forward slash as a separator to say that it emits deprecation warnings with ID 'slash-div'.
'slash-div': Deprecation<'slash-div'>;
bogus-combinatorsDeprecation for leading, trailing, and repeated combinators.
Update the proposal for bogus combinators to say that it emits deprecation warnings with ID 'bogus-combinators'.
'bogus-combinators': Deprecation<'bogus-combinators'>;
strict-unaryDeprecation for ambiguous + and - operators.
Update the proposal for strict unary operators to say that it emits deprecation warnings with ID 'strict-unary'.
'strict-unary': Deprecation<'strict-unary'>;
function-unitsDeprecation for passing invalid units to certain built-in functions.
Update the proposals for function units, random with units, and angle units to say that they emit deprecation warnings with ID 'function-units'.
'function-units': Deprecation<'function-units'>;
duplicate-var-flagsDeprecation for using multiple !global or !default flags on a single
variable.
This deprecation was never explicitly listed in a proposal.
'duplicate-var-flags': Deprecation<'duplicate-var-flags'>;
importDeprecation for @import rules.
Update the proposal for the module system to say that, when @import is
deprecated, Sass will emit deprecation warnings with ID 'import' when @import
rules are encountered.
import: Deprecation<'import'>;
user-authoredUsed for deprecations coming from user-authored code.
'user-authored': Deprecation<'user-authored', 'user'>;
} // Deprecations
DeprecationOrIdA deprecation, or the ID of one.
export type DeprecationOrId = Deprecation | keyof Deprecations;
DeprecationStatusA deprecation's status.
export type DeprecationStatus = 'active' | 'user' | 'future' | 'obsolete';
DeprecationA deprecated feature in the language.
export interface Deprecation<
id extends keyof Deprecations = keyof Deprecations,
status extends DeprecationStatus = DeprecationStatus
> {
idA kebab-case ID for this deprecation.
id: id;
The status of this deprecation.
deprecatedIn is
non-null and obsoleteIn is null.deprecatedIn
and obsoleteIn are null.deprecatedIn and
obsoleteIn are null.deprecatedIn and obsoleteIn are non-null.status: status;
descriptionA brief user-readable description of this deprecation.
description?: string;
deprecatedInThe compiler version this feature was first deprecated in.
This is implementation-dependent, so versions are not guaranteed to be consistent between different compilers. For future deprecations, or those originating from user-authored code, this is null.
deprecatedIn: status extends 'future' | 'user' ? null : Version;
obsoleteInThe compiler version this feature was fully removed in, making the deprecation obsolete.
This is null for active and future deprecations.
obsoleteIn: status extends 'obsolete' ? Version : null;
} // Deprecation
VersionA semantic version of the compiler.
export class Version {
Creates a new Version with its major, minor, and patch fields set to the
corresponding arguments.
constructor(major: number, minor: number, patch: number);
majorThe major version.
This must be a non-negative integer.
readonly major: number;
minorThe minor version.
This must be a non-negative integer.
readonly minor: number;
patchThe patch version.
This must be a non-negative integer.
readonly patch: number;
parseParses a string in the form "major.minor.patch" into a Version.
static parse(version: string): Version;
} // Version
declare module '../spec/js-api' {
deprecationsAn object containing all of the deprecations.
export const deprecations: Deprecations;
} // module
fatal_deprecationA set of deprecation IDs to treat as fatal.
If a deprecation warning of any provided type is encountered during compilation,
the compiler must respond with a CompileFailure instead of a CompileSuccess.
The compiler must emit an event of type LogEventType.WARNING if any of the
following is true:
future_deprecationsilence_deprecation
(making it fatal takes precedence)repeated string fatal_deprecation = 15;
silence_deprecationA set of deprecation IDs to ignore.
If a deprecation warning of any provided type is encountered during compilation, the compiler must ignore it.
The compiler must emit an event of type LogEventType.WARNING if an invalid
deprecation ID or any non-active deprecation ID is passed here.
If a future deprecation ID is passed both here and to future_deprecation, then
silencing it takes precedence.
repeated string silence_deprecation = 16;
future_deprecationA set of future deprecations IDs to opt into early.
For each future deprecation ID provided here, the compiler must treat that
deprecation as if it is active, emitting warnings as necessary (subject to
fatal_deprecation and silence_deprecation).
The compiler must emit an event of type LogEventType.WARNING if an invalid
deprecation ID or any non-future deprecation ID is passed here.
repeated string future_deprecation = 17;
deprecation_typeThe deprecation ID for this warning, if type is
LogEventType.DEPRECATION_WARNING.
optional string deprecation_type = 7;