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

[BUGFIX beta] Refactor ember-debug to support better prod stripping. #15224

Merged
merged 1 commit into from
May 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions packages/ember-debug/lib/deprecate.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*global __fail__*/
import { DEBUG } from 'ember-env-flags';

import EmberError from './error';
import Logger from 'ember-console';
Expand All @@ -7,6 +8,11 @@ import { ENV } from 'ember-environment';

import { registerHandler as genericRegisterHandler, invoke } from './handlers';

/**
@module ember
@submodule ember-debug
*/

/**
Allows for runtime registration of handler functions that override the default deprecation behavior.
Deprecations are invoked by calls to [Ember.deprecate](http://emberjs.com/api/classes/Ember.html#method_deprecate).
Expand Down Expand Up @@ -42,11 +48,15 @@ import { registerHandler as genericRegisterHandler, invoke } from './handlers';
@param handler {Function} A function to handle deprecation calls.
@since 2.1.0
*/
export function registerHandler(handler) {
let registerHandler = () => {};
let missingOptionsDeprecation, missingOptionsIdDeprecation, missingOptionsUntilDeprecation, deprecate;

if (DEBUG) {
registerHandler = function registerHandler(handler) {
genericRegisterHandler('deprecate', handler);
}

function formatMessage(_message, options) {
let formatMessage = function formatMessage(_message, options) {
let message = _message;

if (options && options.id) {
Expand Down Expand Up @@ -116,16 +126,11 @@ registerHandler(function raiseOnDeprecation(message, options, next) {
}
});

export let missingOptionsDeprecation = 'When calling `Ember.deprecate` you ' +
missingOptionsDeprecation = 'When calling `Ember.deprecate` you ' +
'must provide an `options` hash as the third parameter. ' +
'`options` should include `id` and `until` properties.';
export let missingOptionsIdDeprecation = 'When calling `Ember.deprecate` you must provide `id` in options.';
export let missingOptionsUntilDeprecation = 'When calling `Ember.deprecate` you must provide `until` in options.';

/**
@module ember
@submodule ember-debug
*/
missingOptionsIdDeprecation = 'When calling `Ember.deprecate` you must provide `id` in options.';
missingOptionsUntilDeprecation = 'When calling `Ember.deprecate` you must provide `until` in options.';

/**
Display a deprecation warning with the provided message and a stack trace
Expand All @@ -150,7 +155,7 @@ export let missingOptionsUntilDeprecation = 'When calling `Ember.deprecate` you
@public
@since 1.0.0
*/
export default function deprecate(message, test, options) {
deprecate = function deprecate(message, test, options) {
if (!options || (!options.id && !options.until)) {
deprecate(
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this cause a stack overflow?

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 had a similar thought, but no because we are passing options and options.id and options.until. If we remove the guarding if (and move those conditions to the deprecate's predicate) it would be a stack overflow.

missingOptionsDeprecation,
Expand Down Expand Up @@ -189,3 +194,13 @@ export default function deprecate(message, test, options) {

invoke('deprecate', ...arguments);
}
}

export default deprecate;

export {
registerHandler,
missingOptionsDeprecation,
missingOptionsIdDeprecation,
missingOptionsUntilDeprecation
}
16 changes: 14 additions & 2 deletions packages/ember-debug/lib/handlers.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { DEBUG } from 'ember-env-flags';

export let HANDLERS = { };

export function registerHandler(type, callback) {
let registerHandler = () => {};
let invoke = () => {};

if (DEBUG) {
registerHandler = function registerHandler(type, callback) {
let nextHandler = HANDLERS[type] || (() => { });

HANDLERS[type] = (message, options) => {
callback(message, options, nextHandler);
};
}

export function invoke(type, message, test, options) {
invoke = function invoke(type, message, test, options) {
if (test) { return; }

let handlerForType = HANDLERS[type];
Expand All @@ -17,3 +23,9 @@ export function invoke(type, message, test, options) {
handlerForType(message, options);
}
}
}

export {
registerHandler,
invoke
}
119 changes: 64 additions & 55 deletions packages/ember-debug/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DEBUG } from 'ember-env-flags'
import { ENV, environment } from 'ember-environment';
import Logger from 'ember-console';
import { isTesting } from './testing';
Expand All @@ -14,16 +15,50 @@ export { default as isFeatureEnabled } from './features';
export { default as Error } from './error';
export { isTesting, setTesting } from './testing';

export let debugFunctions = {
assert() {},
info() {},
warn() {},
debug() {},
deprecate() {},
deprecateFunc(...args) { return args[args.length - 1]; },
debugSeal() {},
debugFreeze() {}
// These are the default production build versions:
let assert = () => {};
let info = () => {};
let warn = () => {};
let debug = () => {};
let deprecate = () => {};
let debugSeal = () => {};
let debugFreeze = () => {};
let runInDebug = () => {};

let deprecateFunc = function() { return arguments[arguments.length - 1]; };

let setDebugFunction = () => {};
let getDebugFunction = () => {};

if (DEBUG) {
setDebugFunction = function(type, callback) {
switch (type) {
case 'assert': return assert = callback;
case 'info': return info = callback;
case 'warn': return warn = callback;
case 'debug': return debug = callback;
case 'deprecate': return deprecate = callback;
case 'debugSeal': return debugSeal = callback;
case 'debugFreeze': return debugFreeze = callback;
case 'runInDebug': return runInDebug = callback;
case 'deprecateFunc': return deprecateFunc = callback;
}
};

getDebugFunction = function(type) {
switch (type) {
case 'assert': return assert;
case 'info': return info;
case 'warn': return warn;
case 'debug': return debug;
case 'deprecate': return deprecate;
case 'debugSeal': return debugSeal;
case 'debugFreeze': return debugFreeze;
case 'runInDebug': return runInDebug;
case 'deprecateFunc': return deprecateFunc;
}
};
}

/**
@module ember
Expand All @@ -35,7 +70,7 @@ export let debugFunctions = {
@public
*/


if (DEBUG) {
/**
Define an assertion that will throw an exception if the condition is not met.

Expand Down Expand Up @@ -167,7 +202,11 @@ setDebugFunction('debugFreeze', function debugFreeze(obj) {
setDebugFunction('deprecate', _deprecate);

setDebugFunction('warn', _warn);
}

let _warnIfUsingStrippedFeatureFlags;

if (DEBUG && !isTesting()) {
/**
Will call `Ember.warn()` if ENABLE_OPTIONAL_FEATURES or
any specific FEATURES flag is truthy.
Expand All @@ -178,7 +217,7 @@ setDebugFunction('warn', _warn);
@method _warnIfUsingStrippedFeatureFlags
@return {void}
*/
export function _warnIfUsingStrippedFeatureFlags(FEATURES, knownFeatures, featuresWereStripped) {
_warnIfUsingStrippedFeatureFlags = function _warnIfUsingStrippedFeatureFlags(FEATURES, knownFeatures, featuresWereStripped) {
if (featuresWereStripped) {
warn('Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.', !ENV.ENABLE_OPTIONAL_FEATURES, { id: 'ember-debug.feature-flag-with-features-stripped' });

Expand All @@ -192,9 +231,8 @@ export function _warnIfUsingStrippedFeatureFlags(FEATURES, knownFeatures, featur
warn(`FEATURE["${key}"] is set as enabled, but FEATURE flags are only available in canary builds.`, !FEATURES[key], { id: 'ember-debug.feature-flag-with-features-stripped' });
}
}
}
};

if (!isTesting()) {
// Complain if they're using FEATURE flags in builds other than canary
FEATURES['features-stripped-test'] = true;
let featuresWereStripped = true;
Expand Down Expand Up @@ -240,46 +278,17 @@ if (runningNonEmberDebugJS) {
warn('Please use `ember.debug.js` instead of `ember.js` for development and debugging.');
}

export function getDebugFunction(name) {
return debugFunctions[name];
}

export function setDebugFunction(name, fn) {
debugFunctions[name] = fn;
}

export function assert() {
return debugFunctions.assert.apply(undefined, arguments);
}

export function info() {
return debugFunctions.info.apply(undefined, arguments);
}

export function warn() {
return debugFunctions.warn.apply(undefined, arguments);
}

export function debug() {
return debugFunctions.debug.apply(undefined, arguments);
}

export function deprecate() {
return debugFunctions.deprecate.apply(undefined, arguments);
}

export function deprecateFunc() {
return debugFunctions.deprecateFunc.apply(undefined, arguments);
}

export function runInDebug() {
return debugFunctions.runInDebug.apply(undefined, arguments);
}

export function debugSeal() {
return debugFunctions.debugSeal.apply(undefined, arguments);
}

export function debugFreeze() {
return debugFunctions.debugFreeze.apply(undefined, arguments);
export {
assert,
info,
warn,
debug,
deprecate,
debugSeal,
debugFreeze,
runInDebug,
deprecateFunc,
setDebugFunction,
getDebugFunction,
_warnIfUsingStrippedFeatureFlags
}
Whitespace-only changes.
33 changes: 24 additions & 9 deletions packages/ember-debug/lib/warn.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { DEBUG } from 'ember-env-flags';

import Logger from 'ember-console';
import deprecate from './deprecate';
import { registerHandler as genericRegisterHandler, invoke } from './handlers';

let registerHandler = () => {};
let warn = () => {};
let missingOptionsDeprecation, missingOptionsIdDeprecation;

/**
@module ember
@submodule ember-debug
*/

if (DEBUG) {
/**
Allows for runtime registration of handler functions that override the default warning behavior.
Warnings are invoked by calls made to [Ember.warn](http://emberjs.com/api/classes/Ember.html#method_warn).
Expand Down Expand Up @@ -30,7 +42,7 @@ import { registerHandler as genericRegisterHandler, invoke } from './handlers';
@param handler {Function} A function to handle warnings.
@since 2.1.0
*/
export function registerHandler(handler) {
registerHandler = function registerHandler(handler) {
genericRegisterHandler('warn', handler);
}

Expand All @@ -41,15 +53,10 @@ registerHandler(function logWarning(message, options) {
}
});

export let missingOptionsDeprecation = 'When calling `Ember.warn` you ' +
missingOptionsDeprecation = 'When calling `Ember.warn` you ' +
'must provide an `options` hash as the third parameter. ' +
'`options` should include an `id` property.';
export let missingOptionsIdDeprecation = 'When calling `Ember.warn` you must provide `id` in options.';

/**
@module ember
@submodule ember-debug
*/
missingOptionsIdDeprecation = 'When calling `Ember.warn` you must provide `id` in options.';

/**
Display a warning with the provided message.
Expand All @@ -69,7 +76,7 @@ export let missingOptionsIdDeprecation = 'When calling `Ember.warn` you must pro
@public
@since 1.0.0
*/
export default function warn(message, test, options) {
warn = function warn(message, test, options) {
if (arguments.length === 2 && typeof test === 'object') {
options = test;
test = false;
Expand Down Expand Up @@ -100,3 +107,11 @@ export default function warn(message, test, options) {

invoke('warn', message, test, options);
}
}

export default warn;
export {
registerHandler,
missingOptionsIdDeprecation,
missingOptionsDeprecation
}
7 changes: 0 additions & 7 deletions packages/ember/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ Ember.Registry = Registry;
// flag plugin works properly
import * as EmberDebug from 'ember-debug';
import { deprecate, deprecateFunc } from 'ember-debug';
import { DEBUG } from 'ember-env-flags';

const computed = metal.computed;
computed.alias = metal.alias;
Expand All @@ -46,12 +45,6 @@ Ember.cacheFor = metal.cacheFor;
Ember.assert = EmberDebug.assert;
Ember.warn = EmberDebug.warn;
Ember.debug = EmberDebug.debug;
Ember.deprecate = function () { };
Ember.deprecateFunc = function() { };
if (DEBUG) {
Ember.deprecate = EmberDebug.deprecate;
Ember.deprecateFunc = EmberDebug.deprecateFunc;
}
Ember.deprecateFunc = EmberDebug.deprecateFunc;
Ember.runInDebug = EmberDebug.runInDebug;
/**
Expand Down
27 changes: 27 additions & 0 deletions packages/ember/tests/production_build_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { DEBUG } from 'ember-env-flags'
import {
assert as emberAssert,
runInDebug
} from 'ember-debug';

QUnit.module('production builds');

if (!DEBUG) {
QUnit.test('assert does not throw in production builds', function(assert) {
assert.expect(1);

try {
emberAssert('Should not throw');
assert.ok(true, 'Ember.assert did not throw');
} catch (e) {
assert.ok(false, `Expected assert not to throw but it did: ${e.message}`);
}
});

QUnit.test('runInDebug does not run the callback in production builds', function(assert) {
let fired = false;
runInDebug(() => fired = true);

assert.equal(fired, false, 'runInDebug callback should not be ran');
});
}