diff --git a/README.md b/README.md index 1407958..e4f0d8a 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,30 @@ In the future, we could resolve this incompatibility if we had access to Embroid Because the intent of this library is to allow users to upgrade to Ember 4.0+ while they still in the process of resolving this-property-fallback deprecations, this library includes the [`this-property-fallback` deprecation from Ember 3.x](https://deprecations.emberjs.com/v3.x#toc_this-property-fallback). You can follow the instructions [here](https://guides.emberjs.com/release/configuring-ember/handling-deprecations/) for handling these deprecations. +## Configuration + +You can configure this addon under the `'ember-this-fallback'` key in the `EmberApp` constructor options: + +```js +"use strict"; + +const EmberApp = require("ember-cli/lib/broccoli/ember-app"); + +module.exports = function (defaults) { + const app = new EmberApp(defaults, { + //... + "ember-this-fallback": { + /** + * Disable all logging, including debug logging (even with the `DEBUG` + * environment variable) and logging to `ember-this-fallback-plugin.log`. + */ + enableLogging: false, + }, + }); + // ... +}; +``` + ## Contributing See the [Contributing](CONTRIBUTING.md) guide for details. diff --git a/ember-cli-build.js b/ember-cli-build.js index f67439b..06af003 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -7,6 +7,11 @@ module.exports = function (defaults) { 'ember-cli-babel': { throwUnlessParallelizable: true, }, + + // Uncomment this to disable logging altogether: + // 'ember-this-fallback': { + // enableLogging: false, + // }, }); /* diff --git a/index.js b/index.js index 3cd1cd7..afa73eb 100644 --- a/index.js +++ b/index.js @@ -1,19 +1,19 @@ 'use strict'; const ThisFallbackPlugin = require('./lib/this-fallback-plugin'); +const getOptions = require('./lib/options').getOptions; module.exports = { name: require('./package').name, setupPreprocessorRegistry(type, registry) { - // This check ensures that the plugin runs only on the app's code, not on - // this addon's own code. if (type === 'parent') { - registry.add('htmlbars-ast-plugin', this._buildPlugin()); + const options = getOptions(findHost(this)); + registry.add('htmlbars-ast-plugin', this._buildPlugin(options)); } }, - _buildPlugin() { + _buildPlugin(options) { ThisFallbackPlugin.baseDir = () => __dirname; ThisFallbackPlugin.cacheKey = () => 'ember-this-fallback'; @@ -22,9 +22,21 @@ module.exports = { parallelBabel: { requireFile: __filename, buildUsing: '_buildPlugin', - params: {}, + params: options, }, - plugin: ThisFallbackPlugin, + plugin: ThisFallbackPlugin(options), }; }, }; + +// HACK: Borrowed from https://github.com/empress/ember-showdown-prism/blob/73a86d5680979c170a8589d723b4ba028bcf81af/index.js#LL42C1-L52C2 +function findHost(addon) { + let current = addon; + let app; + + do { + app = current.app || app; + } while (current.parent.parent && (current = current.parent)); + + return app; +} diff --git a/lib/helpers/logger.ts b/lib/helpers/logger.ts index 6456a2b..2658b60 100644 --- a/lib/helpers/logger.ts +++ b/lib/helpers/logger.ts @@ -5,22 +5,48 @@ import { format, transports, type Logform, - type Logger, } from 'winston'; import Transport from 'winston-transport'; -export { type Logger } from 'winston'; +export interface Logger { + debug: LeveledLogMethod; + warn: LeveledLogMethod; + error: LeveledLogMethod; +} + +type RawMessage = string | string[]; + +interface LeveledLogMethod { + (message: RawMessage, ...meta: unknown[]): void; + (infoObject: Partial): void; +} + +interface LogInfo { + message: RawMessage; + loc?: SourceSpan; +} -type LogInfo = Logform.TransformableInfo & { - label: string; - timestamp: string; -}; +type FormattedLogInfo = Omit & + Omit & { + message: string; + level: string; + label: string; + timestamp: string; + }; + +export function noopLogger(): Logger { + return { + debug: noop, + warn: noop, + error: noop, + }; +} export default function createLogger(namespace: string, label: string): Logger { const debug = _debug(namespace); class DebugTransport extends Transport { - public override log(info: LogInfo, next: () => void): void { + public override log(info: FormattedLogInfo, next: () => void): void { debug(info[Symbol.for('message')]); next(); } @@ -64,18 +90,14 @@ const joinLines = format((info) => { return info; }); -const logFormatter = format.printf( - ({ level, label, timestamp, message, loc }) => { - return `${String(timestamp)} [${level}] ${concatMessage( - String(label), - String(message), - loc as SourceSpan | undefined - )}`; - } -); +const logFormatter = format.printf((info) => { + const { level, label, timestamp, message, loc } = info as FormattedLogInfo; + return `${timestamp} [${level}] ${concatMessage(label, message, loc)}`; +}); -const debugFormatter = format.printf(({ label, message }) => { - return concatMessage(String(label), String(message)); +const debugFormatter = format.printf((info) => { + const { label, message } = info as FormattedLogInfo; + return concatMessage(label, message); }); function concatMessage( @@ -93,3 +115,5 @@ function concatMessage( function joinLogLines(lines: string[]): string { return lines.join('\n\t'); } + +function noop(): void {} diff --git a/lib/options.ts b/lib/options.ts new file mode 100644 index 0000000..dc5f472 --- /dev/null +++ b/lib/options.ts @@ -0,0 +1,17 @@ +import { z } from 'zod'; + +interface Parent { + options: Record; +} + +const EmberThisFallbackOptions = z + .object({ + enableLogging: z.boolean().default(true), + }) + .default({}); + +export type EmberThisFallbackOptions = z.infer; + +export function getOptions({ options }: Parent): EmberThisFallbackOptions { + return EmberThisFallbackOptions.parse(options['ember-this-fallback']); +} diff --git a/lib/this-fallback-plugin.ts b/lib/this-fallback-plugin.ts index 36d874e..13b4a19 100644 --- a/lib/this-fallback-plugin.ts +++ b/lib/this-fallback-plugin.ts @@ -30,9 +30,10 @@ import { needsFallback, wrapWithTryLookup, } from './helpers/fallback'; -import createLogger, { type Logger } from './helpers/logger'; +import createLogger, { noopLogger, type Logger } from './helpers/logger'; import ScopeStack, { unusedNameLike } from './helpers/scope-stack'; import { squish } from './helpers/string'; +import { type EmberThisFallbackOptions } from './options'; import assert from './types/assert'; type Env = WithJSUtils & { @@ -288,20 +289,34 @@ class NoopPlugin implements ASTPlugin { visitor = {}; } -const buildThisFallbackPlugin: ASTPluginBuilder = (env) => { - const name = 'ember-this-fallback'; - const logger = createLogger(`${name}-plugin`, env.moduleName); +function buildThisFallbackPlugin({ + enableLogging, +}: EmberThisFallbackOptions): ASTPluginBuilder { + return (env) => { + const name = 'ember-this-fallback'; + const logger = enableLogging + ? createLogger(`${name}-plugin`, env.moduleName) + : noopLogger(); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (env.meta.jsutils) { - return new ThisFallbackPlugin(name, env, logger); - } else { - logger.error([ - 'The this-fallback-plugin relies on the JSUtils from babel-plugin-ember-template-compilation, but none were found.', - 'To resolve this issue, please ensure you are running the latest version of ember-cli-htmlbars.', - ]); - return new NoopPlugin(name); - } -}; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (env.meta.jsutils) { + return new ThisFallbackPlugin(name, env, logger); + } else { + const errorMessage = [ + 'The this-fallback-plugin relies on the JSUtils from babel-plugin-ember-template-compilation, but none were found.', + 'To resolve this issue, please ensure you are running the latest version of ember-cli-htmlbars.', + ]; + if (enableLogging) { + logger.error([ + 'The this-fallback-plugin relies on the JSUtils from babel-plugin-ember-template-compilation, but none were found.', + 'To resolve this issue, please ensure you are running the latest version of ember-cli-htmlbars.', + ]); + return new NoopPlugin(name); + } else { + throw new Error(errorMessage.join(' ')); + } + } + }; +} export = buildThisFallbackPlugin; diff --git a/package.json b/package.json index a9fac96..083e965 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "ember-cli-htmlbars": "^6.2.0", "ember-cli-typescript": "^5.2.1", "lodash": "^4.17.21", - "winston": "^3.8.2" + "winston": "^3.8.2", + "zod": "^3.21.4" }, "devDependencies": { "@babel/core": "^7.21.8", diff --git a/yarn.lock b/yarn.lock index 0b0bb13..7cc2d38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13241,3 +13241,8 @@ yocto-queue@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== + +zod@^3.21.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" + integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==