From db9998db182f21d1305ebc4c61199ecf7682513f 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 | 57 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/ember/index.js b/packages/ember/index.js index 130d5f33ed5f..53a6fb2eded7 100644 --- a/packages/ember/index.js +++ b/packages/ember/index.js @@ -27,10 +27,22 @@ 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()\`, which is usually defined in app/app.js. +The reason for this is that @embroider/macros, which is used under the hood to handle environment config, requires serializable configuration.`, + ); + } + + this.options['@embroider/macros'].setOwnConfig.sentryConfig = addonConfig; + + this._super.included.apply(this, arguments); }, contentFor(type, config) { @@ -50,3 +62,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]'; +}