Skip to content

Commit

Permalink
Merge pull request #1815 from embroider-build/static-macros-config
Browse files Browse the repository at this point in the history
Make macro configs static
  • Loading branch information
simonihmig committed Feb 27, 2024
2 parents 303cd2e + e55b055 commit f60adbb
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 19 deletions.
33 changes: 30 additions & 3 deletions packages/macros/src/babel/evaluate-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type State from './state';
import dependencySatisfies from './dependency-satisfies';
import moduleExists from './module-exists';
import getConfig from './get-config';
import assertNever from 'assert-never';

type OpValue = string | boolean | number;

Expand Down Expand Up @@ -388,13 +389,39 @@ export class Evaluator {
return { confident: true, value: moduleExists(path, this.state), hasRuntimeImplementation: false };
}
if (callee.referencesImport('@embroider/macros', 'getConfig')) {
return { confident: true, value: getConfig(path, this.state, 'package'), hasRuntimeImplementation: true };
return { confident: true, value: getConfig(path, this.state, 'package'), hasRuntimeImplementation: false };
}
if (callee.referencesImport('@embroider/macros', 'getOwnConfig')) {
return { confident: true, value: getConfig(path, this.state, 'own'), hasRuntimeImplementation: true };
return { confident: true, value: getConfig(path, this.state, 'own'), hasRuntimeImplementation: false };
}
if (callee.referencesImport('@embroider/macros', 'getGlobalConfig')) {
return { confident: true, value: getConfig(path, this.state, 'getGlobalConfig'), hasRuntimeImplementation: true };
// Check for getGlobalConfig().fastboot.isRunning, which is the only pattern in use where config actually needs to have a runtime implementation.
// For compatibility reasons we will continue to support that. All other cases of macro configs are static now.
let maybeFastbootMemberExpression = path.parentPath;
if (
maybeFastbootMemberExpression.isMemberExpression() ||
maybeFastbootMemberExpression.isOptionalMemberExpression()
) {
let maybeFastbootProperty = maybeFastbootMemberExpression.isMemberExpression()
? maybeFastbootMemberExpression.get('property')
: maybeFastbootMemberExpression.isOptionalMemberExpression()
? maybeFastbootMemberExpression.get('property')
: assertNever(maybeFastbootMemberExpression);

if (maybeFastbootProperty.isIdentifier() && maybeFastbootProperty.node.name === 'fastboot') {
return {
confident: true,
value: getConfig(path, this.state, 'getGlobalConfig'),
hasRuntimeImplementation: true,
};
}
}

return {
confident: true,
value: getConfig(path, this.state, 'getGlobalConfig'),
hasRuntimeImplementation: false,
};
}
if (callee.referencesImport('@embroider/macros', 'isDevelopingApp')) {
return {
Expand Down
40 changes: 38 additions & 2 deletions packages/macros/tests/babel/eval.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,21 +164,57 @@ describe('hasRuntimeImplementation', function () {
let code = transform(`
import { getConfig } from '@embroider/macros';
const result = getConfig('foo')`);
expect(code).toMatch(`result = true`);
expect(code).toMatch(`result = false`);
});

test('getConfig property access', () => {
let code = transform(`
import { getConfig } from '@embroider/macros';
const result = getConfig('foo').bar`);
expect(code).toMatch(`result = false`);
});

// this is throwing internally, not sure how to fix
test.skip('getOwnConfig', () => {
let code = transform(`
import { getOwnConfig } from '@embroider/macros';
const result = getOwnConfig()`);
expect(code).toMatch(`result = true`);
expect(code).toMatch(`result = false`);
});

test('getGlobalConfig', () => {
let code = transform(`
import { getGlobalConfig } from '@embroider/macros';
const result = getGlobalConfig()`);
expect(code).toMatch(`result = false`);
});

test('getGlobalConfig property access', () => {
let code = transform(`
import { getGlobalConfig } from '@embroider/macros';
const result = getGlobalConfig().foo`);
expect(code).toMatch(`result = false`);
});

test('getGlobalConfig fastboot access', () => {
let code = transform(`
import { getGlobalConfig } from '@embroider/macros';
const result = getGlobalConfig().fastboot`);
expect(code).toMatch(`result = true`);
});

// fastboot.isRunning relies on dynamic evaluation at runtime. For backwards compatibility we keep it working. See https://github.com/embroider-build/embroider/issues/1804
test('getGlobalConfig fastboot.isRunning access', () => {
let code = transform(`
import { getGlobalConfig } from '@embroider/macros';
const result = getGlobalConfig().fastboot.isRunning`);
expect(code).toMatch(`result = true`);
});

test('getGlobalConfig fastboot?.isRunning access', () => {
let code = transform(`
import { getGlobalConfig } from '@embroider/macros';
const result = getGlobalConfig().fastboot?.isRunning`);
expect(code).toMatch(`result = true`);
});

Expand Down
15 changes: 1 addition & 14 deletions packages/macros/tests/babel/macro-condition.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ describe('macroCondition', function () {
expect(code).not.toMatch(/beta/);
});

buildTimeTest('can see booleans inside getConfig', () => {
test('can see booleans inside getConfig', () => {
let code = transform(`
import { macroCondition, getConfig } from '@embroider/macros';
export default function() {
Expand All @@ -373,19 +373,6 @@ describe('macroCondition', function () {
expect(code).not.toMatch(/alpha/);
});

runTimeTest('can see booleans inside getConfig', () => {
let code = transform(`
import { macroCondition, getConfig } from '@embroider/macros';
export default function() {
// this deliberately chains three kinds of property access syntax: by
// identifier, by numeric index, and by string literal.
return macroCondition(getConfig('qunit').items[0]["other"]) ? 'alpha' : 'beta';
}
`);
expect(run(code, { filename })).toBe('beta');
expect(code).toMatch(/alpha/);
});

if (transform.babelMajorVersion === 7) {
buildTimeTest('can be used as class field initializer', () => {
let code = transform(`
Expand Down

0 comments on commit f60adbb

Please sign in to comment.