Skip to content

Commit 6c8a418

Browse files
authored
Merge pull request #39 from rwjblue/lazy-assert-messages
Update `assert` to prefix predicate when possible.
2 parents 3d4a616 + ae56e9f commit 6c8a418

File tree

10 files changed

+162
-52
lines changed

10 files changed

+162
-52
lines changed

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ The plugin takes 5 types options: `envFlags`, `features`, `debugTools`, `externa
1717
},
1818
// @required
1919
debugTools: {
20-
source: 'debug-tools'
20+
source: 'debug-tools',
21+
// @optional
22+
assertPredicateIndex: 0
2123
},
2224
// @optional
2325
features: {
@@ -94,6 +96,11 @@ Expands into:
9496

9597
## `assert` macro expansion
9698

99+
The `assert` macro can expand in a more intelligent way with the correct
100+
configuration. When `babel-plugin-debug-macros` is provided with the
101+
`assertPredicateIndex` the predicate is injected in front of the assertion
102+
in order to avoid costly assertion message generation when not needed.
103+
97104
```javascript
98105
import { assert } from 'debug-tools';
99106

@@ -102,10 +109,15 @@ assert((() => {
102109
})(), 'You bad!');
103110
```
104111

105-
Expands into:
112+
With the `debugTools: { assertPredicateIndex: 0 }` configuration the following expansion is done:
106113

107-
```javascript
114+
```js
115+
(true && !((() => { return 1 === 1;})()) && console.assert(false, 'this is a warning'));
116+
```
117+
118+
When `assertPredicateIndex` is not specified, the following expansion is done:
108119

120+
```javascript
109121
(true && console.assert((() => { return 1 === 1;})(), 'this is a warning'));
110122
```
111123

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
(true && console.assert((() => true)(), 'This is an assertion'));
2-
(true && console.assert(false, 'This is an assertion 2'));
1+
(true && !((() => true)()) && console.assert(false, 'This is an assertion'));
2+
(true && !(false) && console.assert(false, 'This is an assertion 2'));
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
3+
if (true) {
4+
doStuff();
5+
}
6+
7+
(true && Ember.warn('This is a warning'));
8+
(true && !(foo) && Ember.assert('Hahahaha', false));
9+
(true && !(true) && Ember.deprecate('This thing is donzo', false, {
10+
id: 'donzo',
11+
until: '4.0.0',
12+
url: 'http://example.com'
13+
}));
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { warn, assert, deprecate } from '@ember/debug';
2+
import { DEBUG } from '@glimmer/env';
3+
4+
if (DEBUG) {
5+
doStuff();
6+
}
7+
8+
warn('This is a warning');
9+
10+
assert('Hahahaha', foo);
11+
12+
deprecate('This thing is donzo', true, {
13+
id: 'donzo',
14+
until: '4.0.0',
15+
url: 'http://example.com'
16+
});

fixtures/global-external-helpers/expectation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(true && __debugHelpers__.warn('This is a warning'));
22
(true && __debugHelpers__.assert('Hahahaha', foo));
3-
(true && !(true) && __debugHelpers__.deprecate('This thing is donzo', true, {
3+
(true && !(true) && __debugHelpers__.deprecate('This thing is donzo', false, {
44
id: 'donzo',
55
until: '4.0.0',
66
url: 'http://example.com'

fixtures/retain-module-external-helpers/expectation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { warn, assert, deprecate } from '@ember/debug-tools';
22

33
(true && warn('This is a warning'));
44
(true && assert('Hahahaha', false));
5-
(true && !(true) && deprecate('This thing is donzo', true, {
5+
(true && !(true) && deprecate('This thing is donzo', false, {
66
id: 'donzo',
77
until: '4.0.0',
88
url: 'http://example.com'

src/lib/utils/builder.js

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
export default class Builder {
2-
constructor(t, module, global) {
2+
constructor(t, options) {
33
this.t = t;
4-
this.module = module;
5-
this.global = global;
4+
this.module = options.module;
5+
this.global = options.global;
6+
this.assertPredicateIndex = options.assertPredicateIndex;
67
this.expressions = [];
78
}
89

@@ -15,16 +16,40 @@ export default class Builder {
1516
*
1617
* ($DEBUG && console.assert($PREDICATE, $MESSAGE));
1718
*
18-
* or
19+
* or (when `assertPredicateIndex` specified)
20+
*
21+
* ($DEBUG && $PREDICATE && console.assert(false, $MESSAGE));
22+
*
23+
* or (`{ externalizeHelpers: { module: true } }`)
1924
*
2025
* ($DEBUG && assert($PREDICATE, $MESSAGE));
2126
*
22-
* or
27+
* or (when `{ externalizeHelpers: { module: true }, debugTools: { source: '...', assertPredicateIndex: 0 } }` specified)
28+
*
29+
* ($DEBUG && $PREDICATE && assert(false, $MESSAGE));
30+
*
31+
* or (when `{ externalizeHelpers: { global: '$GLOBLA_NS' }` specified)
2332
*
2433
* ($DEBUG && $GLOBAL_NS.assert($PREDICATE, $MESSAGE));
34+
*
35+
* or (when `{ externalizeHelpers: { global: '$GLOBLA_NS' }, debugTools: { source: '...', assertPredicateIndex: 0 } }` specified)
36+
*
37+
* ($DEBUG && $PREDICATE && $GLOBAL_NS.assert(false, $MESSAGE));
2538
*/
2639
assert(path) {
27-
this._createMacroExpression(path);
40+
let predicate;
41+
if (this.assertPredicateIndex !== undefined) {
42+
predicate = (expression, args) => {
43+
let predicate = args[this.assertPredicateIndex];
44+
args[this.assertPredicateIndex] = this.t.identifier('false');
45+
46+
return predicate;
47+
};
48+
}
49+
50+
this._createMacroExpression(path, {
51+
predicate
52+
});
2853
}
2954

3055
/**
@@ -69,24 +94,40 @@ export default class Builder {
6994
this._createMacroExpression(path);
7095
}
7196

72-
_createMacroExpression(path) {
97+
_createMacroExpression(path, _options) {
98+
let options = _options || {};
99+
73100
let { t, module, global } = this;
74101
let expression = path.node.expression;
75102
let { callee, arguments: args } = expression;
76103
let callExpression;
77104

105+
if (options.validate) {
106+
options.validate(expression, args);
107+
}
108+
78109
if (module || global) {
79110
if (global) {
80111
callExpression = this._createGlobalExternalHelper(callee, args, global);
81112
} else {
82113
callExpression = expression;
83114
}
115+
} else if (options.buildConsoleAPI) {
116+
callExpression = options.buildConsoleAPI(expression, args);
84117
} else {
85-
callExpression = this._createConsoleAPI(callee, args);
118+
callExpression = this._createConsoleAPI(options.consoleAPI || callee, args);
86119
}
87120

88121
let identifiers = this._getIdentifiers(args);
89-
this.expressions.push([path, this._buildLogicalExpressions([], callExpression)]);
122+
let prefixedIdentifiers = [];
123+
124+
if (options.predicate) {
125+
let predicate = options.predicate(expression, args);
126+
let negatedPredicate = t.unaryExpression('!', t.parenthesizedExpression(predicate));
127+
prefixedIdentifiers.push(negatedPredicate);
128+
}
129+
130+
this.expressions.push([path, this._buildLogicalExpressions(prefixedIdentifiers, callExpression)]);
90131
}
91132

92133
/**
@@ -108,41 +149,39 @@ export default class Builder {
108149
*
109150
* or
110151
*
111-
* ($DEBUG && $PREDICATE && deprecate($MESSAGE, $PREDICATE, { $ID, $URL, $UNTIL }));
152+
* ($DEBUG && $PREDICATE && deprecate($MESSAGE, false, { $ID, $URL, $UNTIL }));
112153
*
113154
* or
114155
*
115-
* ($DEBUG && $PREDICATE && $GLOBAL_NS.deprecate($MESSAGE, $PREDICATE, { $ID, $URL, $UNTIL }));
156+
* ($DEBUG && $PREDICATE && $GLOBAL_NS.deprecate($MESSAGE, false, { $ID, $URL, $UNTIL }));
116157
*/
117158
deprecate(path) {
118-
let { t, module, global } = this;
119-
let expression = path.node.expression;
120-
let callee = expression.callee;
121-
let args = expression.arguments;
122-
let [ message, predicate, meta ] = args;
159+
this._createMacroExpression(path, {
160+
predicate: (expression, args) => {
161+
let [, predicate] = args;
162+
args[1] = this.t.identifier('false');
123163

124-
if (meta && meta.properties && !meta.properties.some( prop => prop.key.name === 'id')) {
125-
throw new ReferenceError(`deprecate's meta information requires an "id" field.`);
126-
}
164+
return predicate;
165+
},
127166

128-
if (meta && meta.properties && !meta.properties.some(prop => prop.key.name === 'until')) {
129-
throw new ReferenceError(`deprecate's meta information requires an "until" field.`);
130-
}
167+
buildConsoleAPI: (expression, args) => {
168+
let [message] = args;
131169

132-
let deprecate;
133-
if (module || global) {
134-
if (global) {
135-
deprecate = this._createGlobalExternalHelper(callee, args, global);
136-
} else {
137-
deprecate = expression;
138-
}
139-
} else {
140-
deprecate = this._createConsoleAPI(t.identifier('warn'), [message]);
141-
}
170+
return this._createConsoleAPI(this.t.identifier('warn'), [message]);
171+
},
172+
173+
validate: (expression, args) => {
174+
let [ , , meta ] = args;
142175

143-
this.expressions.push([path, this._buildLogicalExpressions([
144-
t.unaryExpression('!', t.parenthesizedExpression(predicate))
145-
], deprecate)]);
176+
if (meta && meta.properties && !meta.properties.some( prop => prop.key.name === 'id')) {
177+
throw new ReferenceError(`deprecate's meta information requires an "id" field.`);
178+
}
179+
180+
if (meta && meta.properties && !meta.properties.some(prop => prop.key.name === 'until')) {
181+
throw new ReferenceError(`deprecate's meta information requires an "until" field.`);
182+
}
183+
}
184+
});
146185
}
147186

148187
/**
@@ -192,4 +231,4 @@ export default class Builder {
192231
return logicalExpressions;
193232
}
194233
}
195-
}
234+
}

src/lib/utils/macros.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ export default class Macros {
1919
this.svelteVersions = options.svelte;
2020
this.featureFlags = options.features || [];
2121
this.debugHelpers = options.externalizeHelpers || {};
22-
let { module, global } = this.debugHelpers;
23-
this.builder = new Builder(t, module, global);
22+
this.builder = new Builder(t, {
23+
module: this.debugHelpers.module,
24+
global: this.debugHelpers.global,
25+
assertPredicateIndex: options.debugTools.assertPredicateIndex
26+
});
2427
}
2528

2629
/**

src/lib/utils/normalize-options.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ export function normalizeOptions(options) {
5252
throw new Error('You must specify `debugTools.source`');
5353
}
5454

55-
let debugToolsImport;
56-
if (debugTools) {
57-
debugToolsImport = debugTools.source;
58-
}
55+
let {
56+
source: debugToolsImport,
57+
assertPredicateIndex
58+
} = debugTools;
5959

6060
let envFlagsImport;
6161
let _envFlags = {};
@@ -82,7 +82,8 @@ export function normalizeOptions(options) {
8282
flags: _envFlags
8383
},
8484
debugTools: {
85-
debugToolsImport
85+
debugToolsImport,
86+
assertPredicateIndex
8687
}
8788
};
88-
}
89+
}

src/tests/debug-tools-test.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ let cases = {
5151
plugins: [
5252
[DebugToolsPlugin, {
5353
debugTools: {
54-
source: '@ember/debug-tools'
54+
source: '@ember/debug-tools',
55+
assertPredicateIndex: 0
5556
},
5657
envFlags: {
5758
source: '@ember/env-flags',
@@ -100,6 +101,31 @@ let cases = {
100101
fixtures: ['global-external-helpers']
101102
},
102103

104+
'ember-cli-babel default configuration': {
105+
transformOptions: {
106+
presets,
107+
plugins: [
108+
[DebugToolsPlugin, {
109+
externalizeHelpers: {
110+
global: 'Ember'
111+
},
112+
debugTools: {
113+
source: '@ember/debug',
114+
assertPredicateIndex: 1
115+
},
116+
envFlags: {
117+
source: '@glimmer/env',
118+
flags: {
119+
DEBUG: true
120+
}
121+
}
122+
}]
123+
]
124+
},
125+
126+
fixtures: ['ember-cli-babel-config']
127+
},
128+
103129
'Retain Module External Test Helpers': {
104130
transformOptions: {
105131
presets,

0 commit comments

Comments
 (0)