-
-
Notifications
You must be signed in to change notification settings - Fork 407
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #65 from pangratz/publicize-log-levels
Deprecation warning handlers
- Loading branch information
Showing
1 changed file
with
176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
- Start Date: 2015-06-30 | ||
- RFC PR: https://github.com/emberjs/rfcs/pull/65 | ||
- Ember Issue: (leave this empty) | ||
|
||
# Summary | ||
|
||
Deprecations and warnings in Ember.js should have configurable runtime handlers. | ||
This allows default behavior (logging, raise when `RAISE_ON_DEPRECATION` is true) | ||
to be overridden by an enviornment (Ember's tests), addon, or other tool | ||
(like the Ember Inspector). | ||
|
||
Ember-Data and the Ember Inspector have both requested a public | ||
API for changing how deprecation and warning messages are handled. The requirements | ||
for these and other requests are complex enough that deferring the message | ||
behavior into a runtime hook is the suggested path. | ||
|
||
# Motivation | ||
|
||
`Ember.deprecate` and `Ember.warn` usually log messages. With `ENV.RAISE_ON_DEPRECATION` | ||
all deprecations will throw an exception. In some scenarios, this | ||
is less than ideal: | ||
|
||
* Ember itself needs a way to silence some deprecations before their usage | ||
is completely removed from tests. For example, many view APIs in Ember 1.13. | ||
* The Ember inspector desires to raise on specific deprecations, or silence | ||
specific deprecations. | ||
* Ember-Data also desires to silence some deprecations in tests | ||
|
||
In [PR #1141](https://github.com/emberjs/ember.js/pull/11419) | ||
a private log level API has been introduced, which allows finer grained control | ||
if specific deprecations should be logged, throwing an error or be silenced | ||
completely. For example: | ||
|
||
```js | ||
Ember.Debug._addDeprecationLevel('my-feature', Ember.Debug._deprecationLevels.LOG); | ||
// ... | ||
Ember.deprecate("x is deprecated, use Y instead", false, { id: 'my-feature' }); | ||
``` | ||
|
||
Initially a public version of this API was discussed, but it quickly became | ||
clear that a runtime hook provided more flexibility without incurring the | ||
cost of a complex log-level API. | ||
|
||
Note that "runtime" refers to Ember itself. A custom handler could be injected | ||
into Ember-CLI's template compilation code. "runtime" in this context still | ||
refers to handling deprecations raised during compilation. | ||
|
||
# Detailed design | ||
|
||
A handler for deprecations can be registered. This handler will be called | ||
with relevent information about a deprecation, including guarantees about | ||
the presence of these items: | ||
|
||
* The deprecation message | ||
* The version number where this deprecation (and feature) will be removed | ||
* The "id" of this deprecation, a stable identifier independent of the message | ||
|
||
Additionally, an application instance may be passed with the options. An example | ||
handler would look like: | ||
|
||
```js | ||
import { registerHandler } from "ember-debug/deprecations"; | ||
|
||
registerHandler(function deprecationHandler(message, options) { | ||
// * message is the deprecation message | ||
// * options.until is the version this deprecation will be removed at | ||
// * options.id is the canonical id for this deprecation | ||
if (options.until === "2.4.0") { | ||
throw new Error(message); | ||
} else { | ||
console.log(message); | ||
} | ||
}); | ||
``` | ||
|
||
Warnings are similar, but will not recieve an `until` value: | ||
|
||
```js | ||
import { registerHandler } from "ember-debug/warnings"; | ||
|
||
registerHandler(function warningHandler(message, options) { | ||
// * message is the warning message | ||
// * options.id is the canonical id for this warning | ||
if (options.id !== 'view.rerender-on-set') { | ||
console.log(message); | ||
} | ||
}); | ||
``` | ||
|
||
##### chained handlers | ||
|
||
Since several handlers may be registered, a method of deferring to a previously | ||
registered handler must be allowed. A third option is passed to handlers, the | ||
function `next` which represents the previously registered handler. | ||
|
||
For example: | ||
|
||
```js | ||
import { registerHandler } from "ember-debug/deprecations"; | ||
|
||
registerHandler(function firstDeprecationHandler(message, options, next) { | ||
console.warn(message); | ||
}); | ||
|
||
registerHandler(function secondDeprecationHandler(message, options, next) { | ||
if (options.until === "2.4.0") { | ||
throw new Error(message); | ||
} | ||
next(...arguments); | ||
}); | ||
``` | ||
|
||
The first registed handler will receive Ember's default behavior as `next`. | ||
|
||
##### new assertions for deprecate and warn | ||
|
||
Ember's APIs for deprecation and warning do not currently require any information | ||
beyond a message. It is proposed that deprecations be **required** to pass | ||
the following information: | ||
|
||
* Message | ||
* Test | ||
* Canonical id (with a format of `package-name.some-id`) | ||
* Release when this deprecation will be stripped | ||
|
||
For example: | ||
|
||
``` | ||
import Ember from "ember"; | ||
Ember.deprecate("Some message", false, { | ||
id: 'ember-routing.query-params', | ||
until: '3.0.0' | ||
}); | ||
``` | ||
|
||
If this information is not present and assertion will be made. | ||
|
||
Warnings likewise will be required to pass a canonical id: | ||
|
||
``` | ||
import Ember from "ember"; | ||
Ember.warn("Some warning", {id: 'ember-debug.something'}); | ||
``` | ||
|
||
##### default handlers | ||
|
||
The default handler for deprecation should be quite simple, and mirrors current | ||
behavior: | ||
|
||
```js | ||
function defaultDeprecationHandler(message, options) { | ||
if (Ember.ENV.RAISE_ON_DEPRECATION) { | ||
throw new Error(format(message, options)); | ||
} else { | ||
console.log(format(message, options)); | ||
} | ||
} | ||
``` | ||
|
||
The default handler for warnings would be simple `console.log`. | ||
|
||
# Drawbacks | ||
|
||
By not providing a robust log-level API, we are punting complexity to the | ||
consumer of this API. For a low-level tooling API such as this one, it seems | ||
and appropriate tradeoff. | ||
|
||
# Alternatives | ||
|
||
Each app can stub out `deprecate` and `warn`. | ||
|
||
# Unresolved questions | ||
|
||
`RAISE_ON_DEPRECATION` could be considered deprecated with this new API. |