Skip to content

Commit

Permalink
fixing cycles around assert
Browse files Browse the repository at this point in the history
  • Loading branch information
ef4 committed Aug 26, 2024
1 parent 8f3b9f7 commit 434fda0
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 56 deletions.
57 changes: 4 additions & 53 deletions packages/@ember/debug/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import defaultDeprecate from './lib/deprecate';
import { isTesting } from './lib/testing';
import type { WarnFunc } from './lib/warn';
import _warn from './lib/warn';
import { assert, setAssert } from './lib/assert';

export { registerHandler as registerWarnHandler } from './lib/warn';
export {
Expand All @@ -27,10 +28,6 @@ export type DebugFunctionType =
| 'runInDebug'
| 'deprecateFunc';

export interface AssertFunc {
(desc: string, condition: unknown): asserts condition;
(desc: string): never;
}
export type DebugFunc = (message: string) => void;
export type DebugSealFunc = (obj: object) => void;
export type DebugFreezeFunc = (obj: object) => void;
Expand All @@ -43,7 +40,7 @@ export type DeprecateFuncFunc = (
) => Function;

export type GetDebugFunction = {
(type: 'assert'): AssertFunc;
(type: 'assert'): typeof assert;
(type: 'info'): InfoFunc;
(type: 'warn'): WarnFunc;
(type: 'debug'): DebugFunc;
Expand All @@ -55,7 +52,7 @@ export type GetDebugFunction = {
};

export type SetDebugFunction = {
(type: 'assert', func: AssertFunc): AssertFunc;
(type: 'assert', func: typeof assert): typeof assert;
(type: 'info', func: InfoFunc): InfoFunc;
(type: 'warn', func: WarnFunc): WarnFunc;
(type: 'debug', func: DebugFunc): DebugFunc;
Expand All @@ -71,7 +68,6 @@ const noop = () => {};

// SAFETY: these casts are just straight-up lies, but the point is that they do
// not do anything in production builds.
let assert: AssertFunc = noop as unknown as AssertFunc;
let info: InfoFunc = noop;
let warn: WarnFunc = noop;
let debug: DebugFunc = noop;
Expand All @@ -94,7 +90,7 @@ if (DEBUG) {
setDebugFunction = function (type: DebugFunctionType, callback: Function) {
switch (type) {
case 'assert':
return (assert = callback as AssertFunc);
return setAssert(callback as typeof assert);
case 'info':
return (info = callback as InfoFunc);
case 'warn':
Expand Down Expand Up @@ -143,51 +139,6 @@ if (DEBUG) {
*/

if (DEBUG) {
/**
Verify that a certain expectation is met, or throw a exception otherwise.
This is useful for communicating assumptions in the code to other human
readers as well as catching bugs that accidentally violates these
expectations.
Assertions are removed from production builds, so they can be freely added
for documentation and debugging purposes without worries of incuring any
performance penalty. However, because of that, they should not be used for
checks that could reasonably fail during normal usage. Furthermore, care
should be taken to avoid accidentally relying on side-effects produced from
evaluating the condition itself, since the code will not run in production.
```javascript
import { assert } from '@ember/debug';
// Test for truthiness
assert('Must pass a string', typeof str === 'string');
// Fail unconditionally
assert('This code path should never be run');
```
@method assert
@static
@for @ember/debug
@param {String} description Describes the expectation. This will become the
text of the Error thrown if the assertion fails.
@param {any} condition Must be truthy for the assertion to pass. If
falsy, an exception will be thrown.
@public
@since 1.0.0
*/
function assert(desc: string): never;
function assert(desc: string, test: unknown): asserts test;
// eslint-disable-next-line no-inner-declarations
function assert(desc: string, test?: unknown): asserts test {
if (!test) {
throw new Error(`Assertion Failed: ${desc}`);
}
}

setDebugFunction('assert', assert);

/**
Display a debug notice.
Expand Down
59 changes: 59 additions & 0 deletions packages/@ember/debug/lib/assert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { DEBUG } from '@glimmer/env';

export interface AssertFunc {
(desc: string, condition: unknown): asserts condition;
(desc: string): never;
}

export let assert: AssertFunc = (() => {}) as unknown as AssertFunc;

export function setAssert(implementation: typeof assert): typeof assert {
assert = implementation;
return implementation;
}

if (DEBUG) {
/**
Verify that a certain expectation is met, or throw a exception otherwise.
This is useful for communicating assumptions in the code to other human
readers as well as catching bugs that accidentally violates these
expectations.
Assertions are removed from production builds, so they can be freely added
for documentation and debugging purposes without worries of incuring any
performance penalty. However, because of that, they should not be used for
checks that could reasonably fail during normal usage. Furthermore, care
should be taken to avoid accidentally relying on side-effects produced from
evaluating the condition itself, since the code will not run in production.
```javascript
import { assert } from '@ember/debug';
// Test for truthiness
assert('Must pass a string', typeof str === 'string');
// Fail unconditionally
assert('This code path should never be run');
```
@method assert
@static
@for @ember/debug
@param {String} description Describes the expectation. This will become the
text of the Error thrown if the assertion fails.
@param {any} condition Must be truthy for the assertion to pass. If
falsy, an exception will be thrown.
@public
@since 1.0.0
*/
function assert(desc: string): never;
function assert(desc: string, test: unknown): asserts test;
// eslint-disable-next-line no-inner-declarations
function assert(desc: string, test?: unknown): asserts test {
if (!test) {
throw new Error(`Assertion Failed: ${desc}`);
}
}
setAssert(assert);
}
2 changes: 1 addition & 1 deletion packages/@ember/debug/lib/deprecate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ENV } from '@ember/-internals/environment';
import { DEBUG } from '@glimmer/env';

import { assert } from '../index';
import { assert } from './assert';
import type { HandlerCallback } from './handlers';
import { invoke, registerHandler as genericRegisterHandler } from './handlers';

Expand Down
2 changes: 1 addition & 1 deletion packages/@ember/debug/lib/inspect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert } from '@ember/debug';
import { assert } from './assert';
const { toString: objectToString } = Object.prototype;
const { toString: functionToString } = Function.prototype;
const { isArray } = Array;
Expand Down
2 changes: 1 addition & 1 deletion packages/@ember/debug/lib/warn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DEBUG } from '@glimmer/env';

import { assert } from '../index';
import { assert } from './assert';
import type { HandlerCallback } from './handlers';
import { invoke, registerHandler as genericRegisterHandler } from './handlers';

Expand Down

0 comments on commit 434fda0

Please sign in to comment.