@embroider/macros
Version:
Standardized build-time macros for ember apps.
114 lines (97 loc) • 3.7 kB
JavaScript
/*
These are the runtime implementations for the javascript macros that have
runtime implementations.
Not every macro has a runtime implementation, some only make sense in the
build and always run there.
Even when we have runtime implementations, we are still careful to emit static
errors during the build wherever possible, and runtime errors when necessary,
so that you're not surprised when you switch from runtime-mode to compile-time
mode.
*/
/*
CAUTION: in classic builds, this file gets shared by all present copies of
@embroider/macros. If you want to change its public API, you need to rename it
and update `pathToRuntime` in ../babel/state.ts to point at it, so that your
babel plugin and runtime will match.
*/
export function each(array) {
if (!Array.isArray(array)) {
throw new Error(`the argument to the each() macro must be an array`);
}
return array;
}
export function macroCondition(predicate) {
return predicate;
}
// This is here as a compile target for `getConfig` and `getOwnConfig` when
// we're in runtime mode. This is not public API to call from your own code.
export function config(packageRoot) {
return runtimeConfig.packages[packageRoot];
}
export function getGlobalConfig() {
return runtimeConfig.global;
}
export function isTesting() {
let g = runtimeConfig.global;
let e = g && g['@embroider/macros'];
return Boolean(e && e.isTesting);
}
export function setTesting(isTesting) {
if (!runtimeConfig.global) {
runtimeConfig.global = {};
}
if (!runtimeConfig.global['@embroider/macros']) {
runtimeConfig.global['@embroider/macros'] = {};
}
runtimeConfig.global['@embroider/macros'].isTesting = Boolean(isTesting);
}
// Welcome intrepid developer!
//
// While this data is "global", this is a private variable.
//
// do not build features based off of its contents,
// or assume it will have the same name in future releases.
const runtimeConfig = globalThis.__embroider_macros__runtime_config__ ||= {};
runtimeConfig.packages ||= {};
runtimeConfig.global ||= {};
// In the off chance there are duplicate copies of @embroider/macros in the dep graph
// (due to the package manager messing up)
// Let's try to merge them together via the above global well known variable
const localConfig = initializeRuntimeMacrosConfig();
Object.assign(runtimeConfig.packages, localConfig.packages);
Object.assign(runtimeConfig.global, localConfig.global);
// this exists to be targeted by our babel plugin
function initializeRuntimeMacrosConfig() {
return { packages: {}, global: {} };
}
function updaterMethods() {
return {
config,
getGlobalConfig,
setConfig(packageRoot, value) {
runtimeConfig.packages[packageRoot] = value;
},
setGlobalConfig(key, value) {
runtimeConfig.global[key] = value;
},
};
}
// this is how runtime config can get injected at boot. I'm not sure yet if this
// should be public API, but we certainly need it internally to set things like
// the global fastboot.isRunning.
//
// consumers of this API push a function onto
// window._embroider_macros_runtime_config. The function is given four methods
// which allow it to read and write the per-package and global configs. The
// reason for allowing both read & write is that merging strategies are up to
// each consumers -- read first, then merge, then write.
//
// For an example user of this API, see where we generate
// embroider_macros_fastboot_init.js' in @embroider/core.
let updaters = typeof window !== 'undefined' ? window._embroider_macros_runtime_config : undefined;
if (updaters) {
let methods = updaterMethods();
for (let updater of updaters) {
updater(methods);
}
}