Skip to content

Commit

Permalink
♻️ Support stringifying element args in asserts + split helpers (#33009)
Browse files Browse the repository at this point in the history
* Standalone assert stringify elements, add i-amphtml-error

* Move helpers to separate module

* Fix typo

* Fix typo: The Sequal

* Fix typo

* Fix import
  • Loading branch information
rcebulko committed Mar 2, 2021
1 parent cc13d05 commit b382b01
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 29 deletions.
23 changes: 10 additions & 13 deletions src/core/assert.js
Expand Up @@ -14,18 +14,12 @@
* limitations under the License.
*/

/** @fileoverview Dependency-free assertion helpers for use in Preact. */
import {
USER_ERROR_SENTINEL,
elementStringOrPassThru,
} from './error-message-helpers';

/**
* Triple zero width space.
*
* This is added to user error messages, so that we can later identify
* them, when the only thing that we have is the message. This is the
* case in many browsers when the global exception handler is invoked.
*
* @const {string}
*/
export const USER_ERROR_SENTINEL = '\u200B\u200B\u200B';
/** @fileoverview Dependency-free assertion helpers for use in Preact. */

/**
* User error class for use in Preact. Use of sentinel string instead of a
Expand Down Expand Up @@ -92,12 +86,15 @@ function assertion(errorCls, shouldBeTruthy, opt_message, var_args) {
firstElement = subValue;
}

return subValue;
return elementStringOrPassThru(subValue);
});

const error = new errorCls(message);
error.messageArray = messageArray;
error.associatedElement = firstElement;
if (firstElement) {
error.associatedElement = firstElement;
firstElement.classList.add('i-amphtml-error');
}
throw error;
}

Expand Down
40 changes: 40 additions & 0 deletions src/core/error-message-helpers.js
@@ -0,0 +1,40 @@
/**
* Copyright 2021 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Triple zero width space.
*
* This is added to user error messages, so that we can later identify
* them, when the only thing that we have is the message. This is the
* case in many browsers when the global exception handler is invoked.
*
* @const {string}
*/
export const USER_ERROR_SENTINEL = '\u200B\u200B\u200B';

/**
* Converts an element to a readable string; all other types are unchanged.
* TODO(rcebulko): Unify with log.js
* @param {*} val
* @return {*}
*/
export function elementStringOrPassThru(val) {
// Do check equivalent to `val instanceof Element` without cross-window bug
if (val?.nodeType == 1) {
return val.tagName.toLowerCase() + (val.id ? `#${val.id}` : '');
}
return val;
}
21 changes: 6 additions & 15 deletions src/log.js
Expand Up @@ -14,7 +14,10 @@
* limitations under the License.
*/

import {USER_ERROR_SENTINEL} from './core/assert';
import {
USER_ERROR_SENTINEL,
elementStringOrPassThru,
} from './core/error-message-helpers';
import {getMode} from './mode';
import {internalRuntimeVersion} from './internal-version';
import {isArray, isEnumValue} from './types';
Expand Down Expand Up @@ -122,7 +125,7 @@ const externalMessagesSimpleTableUrl = () =>
* @return {string}
*/
const messageArgToEncodedComponent = (arg) =>
encodeURIComponent(String(elementStringOrPassthru(arg)));
encodeURIComponent(String(elementStringOrPassThru(arg)));

/**
* Logging class. Use of sentinel string instead of a boolean to check user/dev
Expand Down Expand Up @@ -632,19 +635,7 @@ export class Log {
* @return {string}
*/
const stringOrElementString = (val) =>
/** @type {string} */ (elementStringOrPassthru(val));

/**
* @param {*} val
* @return {*}
*/
function elementStringOrPassthru(val) {
// Do check equivalent to `val instanceof Element` without cross-window bug
if (val && val.nodeType == 1) {
return val.tagName.toLowerCase() + (val.id ? '#' + val.id : '');
}
return val;
}
/** @type {string} */ (elementStringOrPassThru(val));

/**
* @param {!Array} array
Expand Down
2 changes: 1 addition & 1 deletion test/unit/test-assert.js
Expand Up @@ -14,8 +14,8 @@
* limitations under the License.
*/

import {USER_ERROR_SENTINEL} from '../../src/core/error-message-helpers';
import {
USER_ERROR_SENTINEL,
pureDevAssert as devAssert,
pureUserAssert as userAssert,
} from '../../src/core/assert';
Expand Down

0 comments on commit b382b01

Please sign in to comment.