Skip to content

Commit

Permalink
feat: runtime logging activation (#9683)
Browse files Browse the repository at this point in the history
* feat: runtime logging activation

* fix bugs

* more fixes

* fix lint

* fix build

* fix more lint

* nicer names
  • Loading branch information
runspired authored Feb 19, 2025
1 parent 6253d05 commit 85b1300
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export default function (babel) {
}
let localBindingName = specifier.node.local.name;
let binding = specifier.scope.getBinding(localBindingName);
const enableRuntimeActivation = Boolean(state.opts.runtimeKey);
const strippableKey = enableRuntimeActivation ? state.opts.runtimeKey : state.opts.configKey;

binding.referencePaths.forEach((p) => {
let negateStatement = false;
let node = p;
Expand All @@ -38,18 +41,85 @@ export default function (babel) {
t.callExpression(state.importer.import(p, '@embroider/macros', 'getGlobalConfig'), []),
t.identifier('WarpDrive')
),
t.identifier(state.opts.configKey)
t.identifier(strippableKey)
),
t.identifier(name)
);

node.replaceWith(
// if (LOG_FOO)
// if (LOG_FOO) {
// // ...
// }
// =>
// if (macroCondition(getGlobalConfig('WarpDrive').debug.LOG_FOO))
// if (macroCondition(getGlobalConfig('WarpDrive').debug.LOG_FOO)) {
// // ...
// }
t.callExpression(state.importer.import(p, '@embroider/macros', 'macroCondition'), [
negateStatement ? t.unaryExpression('!', getConfig) : getConfig,
])
);

if (enableRuntimeActivation) {
// we do not yet support arbitrary runtime activation locations,
// the only supported locations are `if (LOG)` style statements, no
// ternaries or other more complex expressions
const parentIfStatement = node.parentPath.type === 'IfStatement' ? node.parentPath : null;
if (!parentIfStatement) {
throw new Error(
`Runtime activation of logging flags is only supported in if statements, but found node '${node.parentPath.type}'`
);
}

// if (LOG_FOO) {
// // ...
// }
// =>
// if (macroCondition(getGlobalConfig('WarpDrive').activeLogging.LOG_FOO)) {
// if (getGlobalConfig('WarpDrive').debug.LOG_FOO || globalThis.getWarpDriveRuntimeConfig().debug.LOG_FOO) {
// // ...
// }
// }
//
// the outer-if is generated by the node-replace above. The inner if is generated here.
const originalBody = parentIfStatement.node.consequent;

// getGlobalConfig('WarpDrive').debug.LOG_FOO
const getActualConfig = t.memberExpression(
t.memberExpression(
t.memberExpression(
t.callExpression(state.importer.import(p, '@embroider/macros', 'getGlobalConfig'), []),
t.identifier('WarpDrive')
),
t.identifier(state.opts.configKey)
),
t.identifier(name)
);

// globalThis.getWarpDriveRuntimeConfig().debug.LOG_FOO
const getRuntimeConfig = t.memberExpression(
t.memberExpression(
t.callExpression(
t.memberExpression(t.identifier('globalThis'), t.identifier('getWarpDriveRuntimeConfig')),
[]
),
t.identifier(state.opts.configKey)
),
t.identifier(name)
);

// <getActualConfig> || <getRuntimeConfig>
const ifExp = t.logicalExpression('||', getActualConfig, getRuntimeConfig);

// if (<negateStatement>(<getActualConfig> || <getRuntimeConfig>)) <originalBody>
const innerIfStatement = t.ifStatement(
negateStatement ? t.unaryExpression('!', ifExp) : ifExp,
originalBody
);

// replace the original body with the new if statement
parentIfStatement.node.consequent = t.blockStatement([innerIfStatement]);
} else {
}
});
specifier.scope.removeOwnBinding(localBindingName);
specifier.remove();
Expand Down
19 changes: 19 additions & 0 deletions packages/build-config/src/-private/utils/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as LOGGING from '../../debugging.ts';

type LOG_CONFIG_KEY = keyof typeof LOGGING;
export type LOG_CONFIG = { [key in LOG_CONFIG_KEY]: boolean };

export function createLoggingConfig(env: { DEBUG: boolean; TESTING: boolean; PRODUCTION: boolean }, debug: LOG_CONFIG) {
const config = {} as LOG_CONFIG;
const keys = Object.keys(LOGGING) as LOG_CONFIG_KEY[];

for (const key of keys) {
if (env.DEBUG || env.TESTING) {
config[key] = true;
} else {
config[key] = debug[key] || false;
}
}

return config;
}
1 change: 1 addition & 0 deletions packages/build-config/src/babel-macros.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export function macros() {
{
source: '@warp-drive/build-config/debugging',
configKey: 'debug',
runtimeKey: 'activeLogging',
flags: config.debug,
},
'@warp-drive/build-config/debugging-stripping',
Expand Down
3 changes: 3 additions & 0 deletions packages/build-config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getDeprecations } from './-private/utils/deprecations.ts';
import { getFeatures } from './-private/utils/features.ts';
import * as LOGGING from './debugging.ts';
import type { MacrosConfig } from '@embroider/macros/src/node.js';
import { createLoggingConfig } from './-private/utils/logging.ts';

const _MacrosConfig = EmbroiderMacros.MacrosConfig as unknown as typeof MacrosConfig;

Expand All @@ -25,6 +26,7 @@ type InternalWarpDriveConfig = {
compatWith: `${number}.${number}` | null;
deprecations: ReturnType<typeof getDeprecations>;
features: ReturnType<typeof getFeatures>;
activeLogging: { [key in LOG_CONFIG_KEY]: boolean };
env: {
TESTING: boolean;
PRODUCTION: boolean;
Expand Down Expand Up @@ -90,6 +92,7 @@ export function setConfig(context: object, appRoot: string, config: WarpDriveCon
compatWith: config.compatWith ?? null,
deprecations: DEPRECATIONS,
features: FEATURES,
activeLogging: createLoggingConfig(env, debugOptions),
env,
};

Expand Down
21 changes: 21 additions & 0 deletions packages/build-config/src/runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { LOG_CONFIG } from './-private/utils/logging';

const RuntimeConfig = {
debug: {},
};

export function getRuntimeConfig() {
return RuntimeConfig;
}

/**
* Upserts the specified logging configuration into the runtime
* config.
*
* globalThis.setWarpDriveLogging({ LOG_PAYLOADS: true } });
*
* @typedoc
*/
export function setLogging(config: Partial<LOG_CONFIG>) {
Object.assign(RuntimeConfig.debug, config);
}
2 changes: 1 addition & 1 deletion packages/build-config/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"include": ["src/**/*"],
"include": ["src/**/**/*"],
"compilerOptions": {
"lib": ["DOM", "ESNext"],
"module": "ESNext",
Expand Down
1 change: 1 addition & 0 deletions packages/build-config/vite.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const entryPoints = [
'./src/debugging.ts',
'./src/deprecations.ts',
'./src/canary-features.ts',
'./src/runtime.ts',
];

export default createConfig(
Expand Down
8 changes: 8 additions & 0 deletions packages/request/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { getRuntimeConfig, setLogging } from '@warp-drive/build-config/runtime';

export { RequestManager as default } from './-private/manager';
export { createDeferred } from './-private/future';
export type { Future, Handler, CacheHandler, NextFn } from './-private/types';
Expand All @@ -12,3 +14,9 @@ export type {
} from '@warp-drive/core-types/request';
export { setPromiseResult, getPromiseResult } from './-private/promise-cache';
export type { Awaitable } from './-private/promise-cache';

// @ts-expect-error adding to globalThis
globalThis.setWarpDriveLogging = setLogging;

// @ts-expect-error adding to globalThis
globalThis.getWarpDriveRuntimeConfig = getRuntimeConfig;
7 changes: 7 additions & 0 deletions packages/store/src/-private/store-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@warp-drive/build-config/deprecations';
import { DEBUG, TESTING } from '@warp-drive/build-config/env';
import { assert } from '@warp-drive/build-config/macros';
import { getRuntimeConfig, setLogging } from '@warp-drive/build-config/runtime';
import type { Cache } from '@warp-drive/core-types/cache';
import type { Graph } from '@warp-drive/core-types/graph';
import type {
Expand Down Expand Up @@ -62,6 +63,12 @@ import { coerceId, ensureStringId } from './utils/coerce-id';
import { constructResource } from './utils/construct-resource';
import { normalizeModelName } from './utils/normalize-model-name';

// @ts-expect-error adding to globalThis
globalThis.setWarpDriveLogging = setLogging;

// @ts-expect-error adding to globalThis
globalThis.getWarpDriveRuntimeConfig = getRuntimeConfig;

export { storeFor };

// We inline this list of methods to avoid importing EmberObject
Expand Down

0 comments on commit 85b1300

Please sign in to comment.