From 03ae0a23e724eccd2efa0991b8e8f445a222fd63 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 24 Oct 2022 17:14:53 +0200 Subject: [PATCH] chore(ember): Show warning when using invalid config When defining Sentry config in `ENV['@sentry/ember'].sentry`, this goes through @embroider/macros under the hood. This relies on config being serializable, which means that e.g. you cannot use regex in the config. To make this easier to pin down (as the error message can be a bit cryptic), this now validates the passed config (based on https://github.com/embroider-build/embroider/pull/1083) and shows a helpful warning message. Note that this also moved this around a bit, leading to config being written only once on build, which should be a bit faster. --- packages/ember/index.js | 55 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/ember/index.js b/packages/ember/index.js index 130d5f33ed5f..01b742c44e0c 100644 --- a/packages/ember/index.js +++ b/packages/ember/index.js @@ -27,10 +27,20 @@ module.exports = { }, }, - config(_, appConfig) { - const addonConfig = appConfig['@sentry/ember']; - this.options['@embroider/macros'].setOwnConfig.sentryConfig = { ...addonConfig }; - return this._super(...arguments); + included() { + const app = this._findHost(); + const config = app.project.config(app.env); + const addonConfig = config['@sentry/ember'] || {}; + + if (!isSerializable(addonConfig)) { + console.warn( + "Warning: You passed a non-serializable config to `ENV['@sentry/ember'].sentry`. Non-serializable config (e.g. RegExp, ...) can only be passed directly to `Sentry.init()`.", + ); + } + + this.options['@embroider/macros'].setOwnConfig.sentryConfig = addonConfig; + + this._super.included.apply(this, arguments); }, contentFor(type, config) { @@ -50,3 +60,40 @@ module.exports = { injectedScriptHashes: [initialLoadHeadSnippetHash, initialLoadBodySnippetHash], }; + +function isSerializable(obj) { + if (isScalar(obj)) { + return true; + } + + if (Array.isArray(obj)) { + return !obj.some(arrayItem => !isSerializable(arrayItem)); + } + + if (isPlainObject(obj)) { + for (let property in obj) { + let value = obj[property]; + if (!isSerializable(value)) { + return false; + } + } + + return true; + } + + return false; +} + +function isScalar(val) { + return ( + typeof val === 'undefined' || + typeof val === 'string' || + typeof val === 'boolean' || + typeof val === 'number' || + val === null + ); +} + +function isPlainObject(obj) { + return typeof obj === 'object' && obj.constructor === Object && obj.toString() === '[object Object]'; +}