Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test babel-plugin-ember-template-compiler alpha #2415

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/compat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"assert-never": "^1.1.0",
"babel-import-util": "^3.0.1",
"babel-plugin-debug-macros": "^1.0.2",
"babel-plugin-ember-template-compilation": "^2.3.0",
"babel-plugin-ember-template-compilation-2": "npm:babel-plugin-ember-template-compilation@^2.4.0",
"babel-plugin-ember-template-compilation": "3.0.0-alpha.4",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babylon": "^6.18.0",
"bind-decorator": "^1.0.11",
Expand Down
11 changes: 8 additions & 3 deletions packages/compat/src/audit/babel-visitor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { NodePath, Node } from '@babel/traverse';
import traverse from '@babel/traverse';
import type { TransformOptions } from '@babel/core';
import { transformSync, types as t } from '@babel/core';
import { transformAsync, types as t } from '@babel/core';
import type { SourceLocation } from '@babel/code-frame';
import { codeFrameColumns } from '@babel/code-frame';

Expand Down Expand Up @@ -29,7 +29,12 @@ export interface ExportAll {
all: string;
}

export function auditJS(rawSource: string, filename: string, babelConfig: TransformOptions, frames: CodeFrameStorage) {
export async function auditJS(
rawSource: string,
filename: string,
babelConfig: TransformOptions,
frames: CodeFrameStorage
) {
if (!babelConfig.ast) {
throw new Error(`module auditing requires a babel config with ast: true`);
}
Expand All @@ -47,7 +52,7 @@ export function auditJS(rawSource: string, filename: string, babelConfig: Transf
let sawDefine: boolean = false;
/* eslint-enable @typescript-eslint/no-inferrable-types */

let { ast, code } = transformSync(rawSource, Object.assign({ filename: filename }, babelConfig))!;
let { ast, code } = (await transformAsync(rawSource, Object.assign({ filename: filename }, babelConfig)))!;
let saveCodeFrame = frames.forSource(rawSource);

traverse(ast!, {
Expand Down
2 changes: 1 addition & 1 deletion packages/compat/src/module-visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ class ModuleVisitor {
): Promise<ParsedInternalModule['parsed'] | Finding[]> {
let rawSource = content.toString('utf8');
try {
let result = auditJS(rawSource, filename, this.params.babelConfig, this.params.frames);
let result = await auditJS(rawSource, filename, this.params.babelConfig, this.params.frames);

for (let problem of result.problems) {
this.params.findings.push({
Expand Down
8 changes: 7 additions & 1 deletion packages/compat/src/v1-addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,13 @@ export default class V1Addon {
],
transforms: plugins,
};
return [require.resolve('babel-plugin-ember-template-compilation'), opts];

let babelVersion = this.addonInstance.addons.find(a => a.name === 'ember-cli-babel')?.pkg.version;
if (babelVersion && semver.satisfies(babelVersion, '< 8.0.0')) {
return [require.resolve('babel-plugin-ember-template-compilation-2'), opts];
} else {
return [require.resolve('babel-plugin-ember-template-compilation'), opts];
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@embroider/reverse-exports": "workspace:*",
"@embroider/shared-internals": "workspace:*",
"assert-never": "^1.2.1",
"babel-plugin-ember-template-compilation": "^2.3.0",
"babel-plugin-ember-template-compilation": "3.0.0-alpha.4",
"broccoli-node-api": "^1.7.0",
"broccoli-persistent-filter": "^3.1.2",
"broccoli-plugin": "^4.0.7",
Expand Down
2 changes: 1 addition & 1 deletion packages/macros/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"@types/node": "^22.9.3",
"@types/resolve": "^1.20.0",
"@types/semver": "^7.3.6",
"babel-plugin-ember-template-compilation": "^2.3.0",
"babel-plugin-ember-template-compilation": "3.0.0-alpha.4",
"code-equality-assertions": "^1.0.1",
"scenario-tester": "^3.0.1",
"typescript": "^5.4.5"
Expand Down
44 changes: 23 additions & 21 deletions packages/macros/tests/glimmer/dependency-satisfies.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,48 @@ describe('dependency satisfies', () => {
project?.dispose();
});

templateTests((transform: (code: string, options?: TemplateTransformOptions) => string) => {
test('in content position', () => {
let result = transform(`{{macroDependencySatisfies 'qunit' '^2.8.0'}}`, { filename });
templateTests((transform: (code: string, options?: TemplateTransformOptions) => Promise<string>) => {
test('in content position', async () => {
let result = await transform(`{{macroDependencySatisfies 'qunit' '^2.8.0'}}`, { filename });
expect(result).toEqual('{{true}}');
});

test('in subexpression position', () => {
let result = transform(`<Foo @a={{macroDependencySatisfies 'qunit' '^2.8.0'}} />`, { filename });
test('in subexpression position', async () => {
let result = await transform(`<Foo @a={{macroDependencySatisfies 'qunit' '^2.8.0'}} />`, { filename });
expect(result).toMatch(/@a=\{\{true\}\}/);
});

test('in branch', () => {
let result = transform(`{{#if (macroDependencySatisfies 'qunit' '^2.8.0')}}red{{else}}blue{{/if}}`, { filename });
test('in branch', async () => {
let result = await transform(`{{#if (macroDependencySatisfies 'qunit' '^2.8.0')}}red{{else}}blue{{/if}}`, {
filename,
});
expect(result).toEqual('red');
});

test('emits false for out-of-range package', () => {
let result = transform(`{{macroDependencySatisfies 'qunit' '^10.0.0'}}`, { filename });
test('emits false for out-of-range package', async () => {
let result = await transform(`{{macroDependencySatisfies 'qunit' '^10.0.0'}}`, { filename });
expect(result).toEqual('{{false}}');
});

test('emits false for missing package', () => {
let result = transform(`{{macroDependencySatisfies 'not-a-real-dep' '^10.0.0'}}`, { filename });
test('emits false for missing package', async () => {
let result = await transform(`{{macroDependencySatisfies 'not-a-real-dep' '^10.0.0'}}`, { filename });
expect(result).toEqual('{{false}}');
});

test('args length error', () => {
expect(() => {
transform(`{{macroDependencySatisfies 'not-a-real-dep'}}`, { filename });
}).toThrow(/macroDependencySatisfies requires two arguments, you passed 1/);
test('args length error', async () => {
await expect(async () => {
await transform(`{{macroDependencySatisfies 'not-a-real-dep'}}`, { filename });
}).rejects.toThrow(/macroDependencySatisfies requires two arguments, you passed 1/);
});

test('non literal arg error', () => {
expect(() => {
transform(`{{macroDependencySatisfies someDep "*"}}`, { filename });
}).toThrow(/all arguments to macroDependencySatisfies must be string literals/);
test('non literal arg error', async () => {
await expect(async () => {
await transform(`{{macroDependencySatisfies someDep "*"}}`, { filename });
}).rejects.toThrow(/all arguments to macroDependencySatisfies must be string literals/);
});

test('it considers prereleases (otherwise within the range) as allowed', () => {
let result = transform(`{{macroDependencySatisfies 'foo' '^1.0.0'}}`, { filename });
test('it considers prereleases (otherwise within the range) as allowed', async () => {
let result = await transform(`{{macroDependencySatisfies 'foo' '^1.0.0'}}`, { filename });
expect(result).toEqual('{{true}}');
});
});
Expand Down
30 changes: 15 additions & 15 deletions packages/macros/tests/glimmer/fail-build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@ import { templateTests } from './helpers';
import type { MacrosConfig } from '../../src/node';

describe(`macroFailBuild`, function () {
templateTests(function (transform: (code: string) => string, config: MacrosConfig) {
templateTests(function (transform: (code: string) => Promise<string>, config: MacrosConfig) {
config.setOwnConfig(__filename, { failureMessage: 'I said so' });
config.finalize();

test('it can fail the build, content position', () => {
expect(() => {
transform(`
test('it can fail the build, content position', async () => {
await expect(async () => {
await transform(`
{{macroFailBuild "This is a deliberate build failure"}};
`);
}).toThrow(/This is a deliberate build failure/);
}).rejects.toThrow(/This is a deliberate build failure/);
});

test('it can fail the build, subexpression position', () => {
expect(() => {
transform(`
test('it can fail the build, subexpression position', async () => {
await expect(async () => {
await transform(`
{{thing (macroFailBuild "This is a deliberate build failure") }};
`);
}).toThrow(/This is a deliberate build failure/);
}).rejects.toThrow(/This is a deliberate build failure/);
});

test('the failure message can incorporate other macro output', () => {
expect(() => {
transform(`
test('the failure message can incorporate other macro output', async () => {
await expect(async () => {
await transform(`
{{macroFailBuild "failing because %s" (macroGetOwnConfig "failureMessage") }};
`);
}).toThrow(/failing because I said so/);
}).rejects.toThrow(/failing because I said so/);
});

test('it does not fail the build when its inside a dead branch', () => {
let code = transform(`
test('it does not fail the build when its inside a dead branch', async () => {
let code = await transform(`
{{if (macroCondition true) someValue (macroFailBuild 'not supposed to happen')}}
}
`);
Expand Down
46 changes: 23 additions & 23 deletions packages/macros/tests/glimmer/get-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { templateTests } from './helpers';
import type { MacrosConfig } from '../../src/node';

describe(`macroGetConfig`, function () {
templateTests(function (transform: (code: string) => string, config: MacrosConfig) {
templateTests(function (transform: (code: string) => Promise<string>, config: MacrosConfig) {
config.setOwnConfig(__filename, {
mode: 'amazing',
count: 42,
Expand All @@ -18,60 +18,60 @@ describe(`macroGetConfig`, function () {

config.finalize();

test('macroGetOwnConfig in content position', function () {
let code = transform(`{{macroGetOwnConfig "mode"}}`);
test('macroGetOwnConfig in content position', async function () {
let code = await transform(`{{macroGetOwnConfig "mode"}}`);
expect(code).toMatch(/\{\{["']amazing["']\}\}/);
});

test('macroGetConfig in content position', function () {
let code = transform(`{{macroGetConfig "scenario-tester" "color"}}`);
test('macroGetConfig in content position', async function () {
let code = await transform(`{{macroGetConfig "scenario-tester" "color"}}`);
expect(code).toMatch(/\{\{["']orange["']\}\}/);
});

test('macroGetOwnConfig in subexpression position', function () {
let code = transform(`{{#let (macroGetOwnConfig "mode") as |m|}}{{m}}{{/let}}`);
test('macroGetOwnConfig in subexpression position', async function () {
let code = await transform(`{{#let (macroGetOwnConfig "mode") as |m|}}{{m}}{{/let}}`);
expect(code).toMatch(/\{\{#with ["']amazing["'] as |m|\}\}/);
});

test('macroGetConfig in subexpression position', function () {
let code = transform(`{{#let (macroGetConfig "scenario-tester" "color") as |m|}}{{m}}{{/let}}`);
test('macroGetConfig in subexpression position', async function () {
let code = await transform(`{{#let (macroGetConfig "scenario-tester" "color") as |m|}}{{m}}{{/let}}`);
expect(code).toMatch(/\{\{#with ["']orange["'] as |m|\}\}/);
});

test('macroGetOwnConfig emits number', function () {
let code = transform(`{{my-assertion (macroGetOwnConfig "count") }}`);
test('macroGetOwnConfig emits number', async function () {
let code = await transform(`{{my-assertion (macroGetOwnConfig "count") }}`);
expect(code).toMatch(/\{\{my-assertion 42\}\}/);
});

test('macroGetOwnConfig emits boolean', function () {
let code = transform(`{{my-assertion (macroGetOwnConfig "inner" "items" "0" "awesome") }}`);
test('macroGetOwnConfig emits boolean', async function () {
let code = await transform(`{{my-assertion (macroGetOwnConfig "inner" "items" "0" "awesome") }}`);
expect(code).toMatch(/\{\{my-assertion true\}\}/);
});

test('macroGetOwnConfig emits string', function () {
let code = transform(`{{my-assertion (macroGetOwnConfig "mode") }}`);
test('macroGetOwnConfig emits string', async function () {
let code = await transform(`{{my-assertion (macroGetOwnConfig "mode") }}`);
expect(code).toMatch(/\{\{my-assertion ['"]amazing['"]\}\}/);
});

test('macroGetOwnConfig emits null', function () {
let code = transform(`{{my-assertion (macroGetOwnConfig "inner" "description") }}`);
test('macroGetOwnConfig emits null', async function () {
let code = await transform(`{{my-assertion (macroGetOwnConfig "inner" "description") }}`);
expect(code).toMatch(/\{\{my-assertion null\}\}/);
});

test('macroGetOwnConfig emits complex pojo', function () {
let code = transform(`{{my-assertion (macroGetOwnConfig) }}`);
test('macroGetOwnConfig emits complex pojo', async function () {
let code = await transform(`{{my-assertion (macroGetOwnConfig) }}`);
expect(code).toMatch(
/\{\{my-assertion \(hash mode=["']amazing["'] count=42 inner=\(hash items=\(array \(hash name=["']Arthur["'] awesome=true\)\) description=null\)\)\}\}/
);
});

test('macroGetOwnConfig emits undefined for missing key', function () {
let code = transform(`{{my-assertion (macroGetOwnConfig "inner" "notAThing") }}`);
test('macroGetOwnConfig emits undefined for missing key', async function () {
let code = await transform(`{{my-assertion (macroGetOwnConfig "inner" "notAThing") }}`);
expect(code).toMatch(/\{\{my-assertion undefined\}\}/);
});

test('macroGetConfig emits undefined for missing config', function () {
let code = transform(`{{my-assertion (macroGetConfig "code-equality-assertions") }}`);
test('macroGetConfig emits undefined for missing config', async function () {
let code = await transform(`{{my-assertion (macroGetConfig "code-equality-assertions") }}`);
expect(code).toMatch(/\{\{my-assertion undefined\}\}/);
});
});
Expand Down
12 changes: 6 additions & 6 deletions packages/macros/tests/glimmer/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { Project } from 'scenario-tester';
import { MacrosConfig } from '../../src/node';
import { join, resolve } from 'path';
import { hbsToJS } from '@embroider/shared-internals';
import { transformSync } from '@babel/core';
import { transformAsync } from '@babel/core';
import type { Options as EtcOptions, Transform } from 'babel-plugin-ember-template-compilation';

const compilerPath = emberTemplateCompiler().path;

export { Project };

type CreateTestsWithConfig = (transform: (templateContents: string) => string, config: MacrosConfig) => void;
type CreateTests = (transform: (templateContents: string) => string) => void;
type CreateTestsWithConfig = (transform: (templateContents: string) => Promise<string>, config: MacrosConfig) => void;
type CreateTests = (transform: (templateContents: string) => Promise<string>) => void;

export interface TemplateTransformOptions {
filename?: string;
Expand All @@ -22,7 +22,7 @@ export function templateTests(createTests: CreateTestsWithConfig | CreateTests)
let config = MacrosConfig.for({}, resolve(__dirname, '..', '..'));
setConfig(config);

let transform = (templateContents: string, options: TemplateTransformOptions = {}) => {
let transform = async (templateContents: string, options: TemplateTransformOptions = {}) => {
let filename = options.filename ?? join(__dirname, 'sample.hbs');

let etcOptions: EtcOptions = {
Expand All @@ -31,13 +31,13 @@ export function templateTests(createTests: CreateTestsWithConfig | CreateTests)
targetFormat: 'hbs',
};

let js = transformSync(hbsToJS(templateContents, { filename: filename }), {
let js = (await transformAsync(hbsToJS(templateContents, { filename: filename }), {
plugins: [
[require.resolve('babel-plugin-ember-template-compilation'), etcOptions],
require.resolve('@babel/plugin-transform-modules-amd'),
],
filename,
})!.code!;
}))!.code!;

let deps: string[];
let impl: Function;
Expand Down
Loading