Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --fatal-deprecations and --future-deprecations #1820

Merged
merged 15 commits into from Mar 10, 2023
Merged

Add --fatal-deprecations and --future-deprecations #1820

merged 15 commits into from Mar 10, 2023

Conversation

jathak
Copy link
Member

@jathak jathak commented Oct 28, 2022

Partial fix for #633 and #1363.

This adds a new Deprecation enum to track the different deprecations that are ongoing or upcoming and allow users to select certain deprecations to treat as fatal (or future deprecations to begin warning for now).

This adds support to the CLI and the Dart API. It does not add support for the JS API yet, but I'd like to land this first so the underlying logic isn't blocked on the language change process.

This adds a new `Deprecation` class that specifies an ID for each
deprecated feature along with what Dart Sass version deprecated it.

The compile functions allow you to pass a set of `fatalDeprecations`
that will cause an error instead of a warning. You can also pass a set
of `futureDeprecations`, which let you opt-in to deprecations (like
`@import`) early.
@jathak jathak marked this pull request as ready for review March 4, 2023 00:57
@jathak jathak requested a review from nex3 March 4, 2023 00:57
Copy link
Contributor

@nex3 nex3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also file issues to track adding this to the JS API and documenting it on the Sass website?

CHANGELOG.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated
Comment on lines 20 to 22
* The optional `deprecation` boolean parameter of the `warn` function is now
deprecated. Use `deprecationType` to pass the specific `Deprecation` being
warned for instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if users are writing custom functions that have behavior that becomes deprecated?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking they would pass Deprecation.userAuthored, but do you think it would make more sense to just leave the boolean parameter un-deprecated? (since right now if they pass deprecation: true with no deprecationType, it defaults to Deprecation.userAuthored)

Or could it be confusing to have both deprecation and deprecationType un-deprecated, since then you could potentially call it with a deprecation type but explicitly pass deprecation: false? (in which case the boolean parameter would be ignored)

Would making deprecation nullable but un-deprecated work?

If we do leave the deprecation un-deprecated in EvaluationContext.warn, should we also do the same for Logger.warn? If we do that, should we just leave the warnForDeprecation extension for Logger as private? (since custom functions should usually be just using Deprecation.userAuthored anyway)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we just have two separate functions for both EvaluationContext and Logger, one for public consumption that takes a boolean deprecation flag and one that's private to Sass which takes a Deprecation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

bin/sass.dart Outdated
Comment on lines 58 to 64
logger: DeprecationHandlingLogger(options.logger,
fatalDeprecations: options.fatalDeprecations,
futureDeprecations: options.futureDeprecations,
// This logger may be reused by multiple parses, so we don't want
// warnings from a previous parse to cause subsequent warnings to
// be skipped.
limitRepetition: false)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a couple questions here:

  • Previously, the Options class was responsible for setting up the logger according to the options passed. Why not do the same with DeprecationHandlingLogger?

  • If we don't limit repetitions here, under what circumstances will we limit repetitions on the CLI?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wrapped logger is only used during parsing. options.logger is wrapped by a DeprecationHandlingLogger again during the actual compilation (this time, with limitRepetition set to true if verbose is false).

This matches the current behavior with the TerseLogger that DeprecationHandlingLogger replaces (repetitions aren't limited for deprecation warnings during parsing). The need to reset the state of DeprecationHandlingLogger is also why we don't just have options.logger produce it.

We could change options.logger to just produce a single DeprecationHandlingLogger, but we'd then need some way for StylesheetGraph and the compiler to reset its state after each run. Do you think that makes more sense instead of wrapping the base logger multiple times?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I think this is fine. It might be worth documenting more of what you just said in the comments, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

lib/sass.dart Outdated Show resolved Hide resolved
lib/src/deprecation.dart Outdated Show resolved Hide resolved
..addMultiOption('fatal-deprecation',
help: 'Deprecations to treat as errors. You may also pass a Sass\n'
'version to include any behavior deprecated in or before it.\n'
'See https://sass-lang.com/documentation/breaking-changes for \n'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update this documentation so that each breaking change includes an example of how to make it fatal as well

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on a sass-site PR now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib/src/executable/options.dart Outdated Show resolved Hide resolved
lib/src/logger.dart Outdated Show resolved Hide resolved
lib/src/logger/deprecation_handling.dart Outdated Show resolved Hide resolved
lib/src/deprecation.dart Outdated Show resolved Hide resolved
@jathak jathak requested a review from nex3 March 6, 2023 18:51
/// For deprecations that have existed in all versions of Dart Sass, this
/// should be 0.0.0. For deprecations that are not yet active, this should be
/// null.
final String? deprecatedIn;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see... real enums strike again. I think the cleanest option given that might be to convert this to a normal class with static final members instead of a literal enum. That's more work to declare, but nicer on the consuming end, which I think it a worthy trade-off.

CHANGELOG.md Outdated
Comment on lines 20 to 22
* The optional `deprecation` boolean parameter of the `warn` function is now
deprecated. Use `deprecationType` to pass the specific `Deprecation` being
warned for instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we just have two separate functions for both EvaluationContext and Logger, one for public consumption that takes a boolean deprecation flag and one that's private to Sass which takes a Deprecation?

bin/sass.dart Outdated
Comment on lines 58 to 64
logger: DeprecationHandlingLogger(options.logger,
fatalDeprecations: options.fatalDeprecations,
futureDeprecations: options.futureDeprecations,
// This logger may be reused by multiple parses, so we don't want
// warnings from a previous parse to cause subsequent warnings to
// be skipped.
limitRepetition: false)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I think this is fine. It might be worth documenting more of what you just said in the comments, though.

lib/src/logger/deprecation_handling.dart Outdated Show resolved Hide resolved
Comment on lines 80 to 81
/// If this is true, `deprecatedIn` should be null, since we do not yet know
/// what version of Dart Sass this deprecation will be live in.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you make this a real class, you can also verify this in a constructor assert().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accomplished this in the enum form by having separate constructors for regular and future deprecations.

@jathak jathak requested a review from nex3 March 9, 2023 23:41
@jathak jathak merged commit 8f8138d into main Mar 10, 2023
@jathak jathak deleted the deprecations branch March 10, 2023 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants