Skip to content
39 changes: 39 additions & 0 deletions docs/guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,42 @@ For example, don't assign a feature to both `css` and `fonts`, since `css` is th

Do assign features to groups when there's an opportunity for future feature composition (see [#971](https://github.com/web-platform-dx/web-features/issues/971)).
For example, several features for the JavaScript `Array` interface are members of the `array` group.

## Discouraged

Rarely, the developers should not use a platform feature because it's the consensus of relevant stakeholders (i.e., a standards body and implementers), even if that feature is still implemented in browsers.
Mark a feature as discouraged when:

- The specification adopts clear language directing developers to stop using that feature or to prefer to an alternative.
This is often through terms like "deprecated", "obsolete", "legacy", or "non-standard."
Copy link
Contributor

Choose a reason for hiding this comment

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

I would omit the "non-standard" part here. There are many non-standard (yet) features that are not discouraged, per se.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, I've removed this with fc94af6. I think it's true—particularly when a spec absorbs some but not all functionality from a non-standard predecessor—but it probably doesn't add clarity here (without more explanation).

They can also be in the form of one-off recommendations to use alternatives (such as "[…ought to be used instead](https://dom.spec.whatwg.org/#ref-for-concept-event%E2%91%A4%E2%91%A3)").

- The specification removes that feature from the specification without a succession plan (such as moving it to another specification).

- The specification editors intend to discourage or remove the feature from the specification.
For example, meeting minutes show that a committee achieved consensus to remove a feature from a specification, even if the removal is not complete.

- All of the (present) implementers issue warnings when using that feature or have published something expressing an intention to unship that feature.


Do not mark a feature as discouraged when:

- The feature is merely old or unpopular, no matter how many [_considered harmful_](https://en.wikipedia.org/wiki/Considered_harmful) blog posts it may have garnered.
For example, despite the existence of `fetch`, `XMLHttpRequest` is not a discouraged feature.

- The feature is controversial.
Opposition to a feature (without consensus) is not sufficient to mark a feature as discouraged.
For example, do not mark a feature as discouraged because a vendor has given it a negative standards position.

- The feature is buggy or not implemented in one or more browsers.
Contribute to accurate support data instead.

When you set a `discouraged` block in a feature file, do:

- Set a (required) `according_to` URL, linking to evidence that the feature is discouraged.
If possible, use the single most broadly applicable reference, such as specification text.
If a feature is removed from a specification, link to an issue, pull request, or commit showing the removal.

- Set one or more (optional) `alternative` feature IDs that are whole or partial substitutes for the discouraged feature.
An alternative doesn't have to be a narrow drop-in replacement for the discouraged feature but it must handle some use case of the discouraged feature.
Guide developers to the most relevant features that would help them stop using the discouraged feature.
1 change: 0 additions & 1 deletion features/symbol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,5 @@ compat_features:
- javascript.builtins.Symbol.toString
- javascript.builtins.Symbol.toStringTag
- javascript.builtins.Symbol.toStringTag.dom_objects
- javascript.builtins.Symbol.unscopables
- javascript.builtins.Symbol.valueOf
- javascript.builtins.Symbol.@@toPrimitive
13 changes: 0 additions & 13 deletions features/symbol.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,6 @@ compat_features:
- javascript.builtins.Symbol.for
- javascript.builtins.Symbol.keyFor

# baseline: high
# baseline_low_date: 2016-08-02
# baseline_high_date: 2019-02-02
# support:
# chrome: "38"
# chrome_android: "38"
# edge: "12"
# firefox: "48"
# firefox_android: "48"
# safari: "9"
# safari_ios: "9"
- javascript.builtins.Symbol.unscopables

# baseline: high
# baseline_low_date: 2016-09-20
# baseline_high_date: 2019-03-20
Expand Down
24 changes: 24 additions & 0 deletions features/with.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: with
description: The `with` JavaScript statement adds a given object to the chain of scopes used to evaluate names.
spec: https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-with-statement
group: javascript
discouraged:
# One thing that is potentially missing here is a "reason" like this:

# reason: browser-warning
# reason: spec-caution
# reason: pending-removal

# This would allow us to signal to tools how "fatal" the discouragement is
# (e.g., pending-removal should trigger noisy errors for developers but spec
# caution would not). I'm not sure the full range of these yet; I think it
# might be easier to choose the set of reasons after we've enumerated a bunch
# of discouraged features.
according_to:
- https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-with-statement
alternatives:
- destructuring
compat_features:
- javascript.statements.with
- javascript.builtins.Symbol.unscopables
- javascript.builtins.Array.@@unscopables
50 changes: 50 additions & 0 deletions features/with.yml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Generated from: with.yml
# Do not edit this file by hand. Edit the source file instead!

status:
baseline: false
support:
chrome: "38"
chrome_android: "38"
edge: "12"
firefox: "48"
firefox_android: "48"
safari: "10"
safari_ios: "10"
Comment on lines +5 to +13
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Given the current Baseline definition, this is correct. That said, I expect consumers (like MDN and caniuse) to choose to suppress the Baseline information when there's a discouragement.

compat_features:
# baseline: high
# baseline_low_date: 2016-08-02
# baseline_high_date: 2019-02-02
# support:
# chrome: "38"
# chrome_android: "38"
# edge: "12"
# firefox: "48"
# firefox_android: "48"
# safari: "9"
# safari_ios: "9"
- javascript.builtins.Symbol.unscopables

# baseline: high
# baseline_low_date: 2016-09-20
# baseline_high_date: 2019-03-20
# support:
# chrome: "38"
# chrome_android: "38"
# edge: "12"
# firefox: "48"
# firefox_android: "48"
# safari: "10"
# safari_ios: "10"
- javascript.builtins.Array.@@unscopables

# baseline: false
# support:
# chrome: "1"
# chrome_android: "18"
# edge: "12"
# firefox: "1"
# firefox_android: "4"
# safari: "1"
# safari_ios: "1"
- javascript.statements.with
10 changes: 10 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,16 @@ for (const [key, data] of yamlEntries('features')) {
features[key] = data;
}

// Assert that discouraged feature's alternatives are valid
for (const [id, feature] of Object.entries(features)) {
for (const alternative of feature.discouraged?.alternatives ?? []) {
console.log(`Confirming ${alternative} in feature set`);
if (!(alternative in features)) {
throw new Error(`${id}'s alternative "${alternative}" is not a valid feature ID`);
}
}
}

const compat = new Compat();
const browsers: Partial<WebFeaturesData["browsers"]> = {};
for (const browser of coreBrowserSet.map(identifier => compat.browser(identifier))) {
Expand Down
9 changes: 6 additions & 3 deletions packages/web-features/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Curated list of Web platform features

This package is experimental, expect frequent breaking changes!

## Usage

```sh
Expand All @@ -27,13 +25,18 @@ import schema from "web-features/data.schema.json" with { type: "json" };

## Rendering Baseline statuses with `web-features`

If you're using `web-features` to render Baseline iconography or browser logos with support markers, then you must follow these procedures to ensure consistent usage.
If you're using `web-features` to render Baseline iconography or browser logos with support markers, then you must follow the [name and logo usage guidelines](https://web-platform-dx.github.io/web-features/name-and-logo-usage-guidelines/).

For Baseline iconography, follow this procedure for each feature:

1. If `status.baseline` is `"high"`, then show an affirmative "widely available" icon.
1. If `status.baseline` is `"low"`, then show an affirmative "newly available" icon.
1. If `status.baseline` is `false`, then show a "limited availability" non-Baseline icon.

**Note**: All features that have the `discouraged` property are, by definition, non-Baseline, and `status.baseline` will be `false`.
If a feature has the `discouraged` property, consider showing a message describing the feature's discouraged status instead of Baseline iconography.
Showing Baseline iconography for discouraged features may confuse readers.

1. If `status.baseline` is `undefined`, then **do not** show any Baseline or non-Baseline badge.

For browser support iconography (that is, browser logos and checkmarks and Xs), follow this procedure for each browser:
Expand Down
24 changes: 24 additions & 0 deletions schemas/data.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,30 @@
"description": "Short description of the feature, as an HTML string",
"type": "string"
},
"discouraged": {
"additionalProperties": false,
"description": "Whether developers are formally discouraged from using this feature",
"properties": {
"according_to": {
"description": "Links to a formal discouragement notice, such as specification text, intent-to-unship, etc.",
"items": {
"description": "URI",
"format": "uri",
"type": "string"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about making this an object with both URI and link text?

Having the URI only forces consumers to come up with some link text on their own (or display the full URI, which isn't great).
This would avoid patterns like: "Discouraged, click here to learn why".

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think this is a good idea, but I'm slightly concerned about us making guesses about what kind of text that consumers would like. I could imagine several different plausible ways to turn discouragement citations into text (I had a try below). I think it might be better to see how MDN and others actually end up using this and what works with developers, before committing to a single way of doing link text.

I do think we should revisit this, like the reason enums.


Possible ways to show this stuff:

All are possible without a handwritten text field.

"type": "array"
},
"alternatives": {
"description": "IDs for features that substitute some or all of this feature's utility",
"items": {},
"type": "array"
}
},
"required": [
"according_to"
],
"type": "object"
},
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a semver minor event.

"group": {
"anyOf": [
{
Expand Down
4 changes: 1 addition & 3 deletions scripts/dist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,7 @@ function toDist(sourcePath: string): YAML.Document {
checkAncestors: true,
});

if (computedStatus.discouraged) {
const isDraft: boolean = source.draft_date ?? false;

if (computedStatus.discouraged && !source.discouraged) {
if (!source.draft_date) {
logger.error(
`${id}: contains at least one deprecated compat feature. This is forbidden for published features.`,
Expand Down
18 changes: 15 additions & 3 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export interface FeatureData {
status: SupportStatus;
/** Sources of support data for this feature */
compat_features?: string[];
/** Whether developers are formally discouraged from using this feature */
discouraged?: Discouraged;
}

type BrowserIdentifier = "chrome" | "chrome_android" | "edge" | "firefox" | "firefox_android" | "safari" | "safari_ios";
Expand All @@ -69,10 +71,20 @@ interface SupportStatus extends Status {
by_compat_key?: Record<string, Status>
}

/** Specification URL
interface Discouraged {
/** Links to a formal discouragement notice, such as specification text, intent-to-unship, etc. */
according_to: uri[];
/** IDs for features that substitute some or all of this feature's utility */
alternatives?: (keyof WebFeaturesData["features"])[];
}

/** URI
* @format uri
*/
type specification_url = string;
*/
type uri = string;

/** Specification URL */
type specification_url = uri;

export interface GroupData {
/** Short name */
Expand Down
Loading