Skip to content

Commit 8ec126f

Browse files
committed
Add embroider telemetry option
1 parent 8144d53 commit 8ec126f

File tree

8 files changed

+2038
-58
lines changed

8 files changed

+2038
-58
lines changed

bin/cli.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,27 @@ const {
77
analyzeEmberObject,
88
getTelemetry,
99
} = require('ember-codemods-telemetry-helpers');
10-
const appLocation = process.argv[2];
11-
const args = process.argv.slice(3);
1210

1311
(async () => {
14-
debug('Gathering telemetry data from %s ...', appLocation);
15-
await gatherTelemetryForUrl(appLocation, analyzeEmberObject);
12+
let args = process.argv;
1613

17-
let telemetry = getTelemetry();
18-
debug('Gathered telemetry on %d modules', Object.keys(telemetry).length);
14+
// FIXME
15+
if (args.includes('--telemetry=runtime')) {
16+
const appLocation = args[2];
17+
18+
debug('Gathering telemetry data from %s ...', appLocation);
19+
await gatherTelemetryForUrl(appLocation, analyzeEmberObject);
20+
21+
let telemetry = getTelemetry();
22+
debug('Gathered telemetry on %d modules', Object.keys(telemetry).length);
23+
24+
args = args.slice(3);
25+
} else {
26+
args = args.slice(2);
27+
}
1928

2029
require('codemod-cli').runTransform(__dirname, 'no-implicit-this', args, 'hbs');
21-
})();
30+
})().catch((error) => {
31+
console.error(error);
32+
process.exit(1);
33+
});

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"test": "jest",
2727
"pretest:integration": "yarn build",
2828
"test:integration": "ts-node ./test/run-test.ts",
29+
"test:integration:embroider": "yarn test:integration --embroider",
30+
"test:integration:runtime": "yarn test:integration --runtime",
2931
"update-docs": "codemod-cli update-docs",
3032
"coveralls": "cat ./coverage/lcov.info | node node_modules/.bin/coveralls",
3133
"lint:js": "eslint .",
@@ -44,6 +46,7 @@
4446
"dependencies": {
4547
"@babel/core": "^7.21.8",
4648
"@babel/preset-env": "^7.21.5",
49+
"@embroider/core": "^3.0.0",
4750
"codemod-cli": "^3.2.0",
4851
"debug": "^4.1.1",
4952
"ember-codemods-telemetry-helpers": "^2.1.0",

test/helpers/sequence.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
import { TestRunner } from './test-runner';
22
import { log } from './utils';
33

4-
export async function runTestIntegrationSequence(version: string) {
4+
export async function runTestIntegrationSequence(
5+
version: string,
6+
mode: 'runtime' | 'embroider'
7+
): Promise<void> {
8+
switch (mode) {
9+
case 'runtime':
10+
return runTestIntegrationSequenceWithRuntimeTelemetry(version);
11+
12+
case 'embroider':
13+
return runTestIntegrationSequenceWithEmbroider(version);
14+
}
15+
}
16+
17+
async function runTestIntegrationSequenceWithRuntimeTelemetry(version: string): Promise<void> {
518
const runner = new TestRunner(version);
619

7-
log(`Running Integration Test for Ember ${version}`);
20+
log(`Running Integration Test for Ember ${version} Using Runtime Telemetry`);
821
log(`Installing Dependencies`);
922
await runner.installDeps();
1023

1124
try {
12-
log(`Starting the Ember Dev Server`);
25+
log(`Starting Ember Dev Server`);
1326
await runner.startEmber();
1427
log(`Running Codemod`);
15-
await runner.runCodemod();
16-
log(`Stopping the Ember Dev Server`);
28+
await runner.runCodemodRuntime();
29+
log(`Stopping Ember Dev Server`);
1730
await runner.stopEmber();
1831
} catch (e) {
19-
log(`Stopping the Ember Dev Server`);
32+
log(`Stopping Ember Dev Server`);
2033
await runner.stopEmber();
2134
throw e;
2235
}
@@ -25,3 +38,18 @@ export async function runTestIntegrationSequence(version: string) {
2538
await runner.compare();
2639
log(`Success`);
2740
}
41+
42+
async function runTestIntegrationSequenceWithEmbroider(version: string): Promise<void> {
43+
const runner = new TestRunner(version);
44+
45+
log(`Running Integration Test for Ember ${version} Using Embroider`);
46+
log(`Installing Dependencies`);
47+
await runner.installDeps();
48+
log(`Running Build`);
49+
await runner.runEmbroiderStage2Build();
50+
log(`Running Codemod`);
51+
await runner.runCodemodEmbroider();
52+
log(`Comparing Results`);
53+
await runner.compare();
54+
log(`Success`);
55+
}

test/helpers/test-runner.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,37 @@ export class TestRunner {
2626
await execa('yarn', ['install'], { cwd: this.inputDir });
2727
}
2828

29-
async runCodemod() {
30-
await execa('../../../../bin/cli.js', ['http://localhost:4200', 'app'], this.execOpts);
29+
async runCodemodRuntime() {
30+
await execa(
31+
'../../../../bin/cli.js',
32+
['http://localhost:4200', 'app', '--telemetry=runtime'],
33+
this.execOpts
34+
);
35+
}
36+
37+
async runCodemodEmbroider() {
38+
await execa('../../../../bin/cli.js', ['app', '--telemetry=embroider'], this.execOpts);
39+
}
40+
41+
async runEmbroiderStage2Build(): Promise<void> {
42+
const process = await execa('yarn', ['ember', 'build'], {
43+
cwd: this.inputDir,
44+
env: {
45+
STAGE2_ONLY: 'true',
46+
},
47+
});
48+
49+
if (process.exitCode !== 0) {
50+
const output = [
51+
`Build failed: STAGE2_ONLY=true yarn ember build exited with ${process.exitCode}\n`,
52+
`=== STDOUT ===\n`,
53+
process.stdout || '(EMPTY)',
54+
`=== STDERR ===\n`,
55+
process.stderr || '(EMPTY)',
56+
];
57+
58+
throw new Error(output.join('\n'));
59+
}
3160
}
3261

3362
async startEmber(): Promise<void> {

test/run-test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ const allVersions = ['3.10', '3.13'];
2020
process.exit(1);
2121
}
2222

23+
const mode = process.argv.includes('--runtime') ? 'runtime' : 'embroider';
24+
2325
let didSucceed = false;
2426

2527
try {
2628
process.env['DEBUG'] = 'true'; // hacks for now
27-
await runTestIntegrationSequence(emberVersion);
29+
await runTestIntegrationSequence(emberVersion, mode);
2830
didSucceed = true;
2931
} catch (e) {
3032
error(e);

transforms/no-implicit-this/helpers/options.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { getOptions as getCLIOptions } from 'codemod-cli';
22
import fs from 'node:fs';
33
import path from 'node:path';
44
import { ZodError, ZodType, z } from 'zod';
5-
import Resolver, { RuntimeResolver } from './resolver';
5+
import Resolver, { EmbroiderResolver, RuntimeResolver } from './resolver';
66

77
export interface Options {
88
customHelpers: string[];
@@ -34,7 +34,7 @@ export function getOptions(): Options {
3434
return {
3535
customHelpers: getCustomHelpersFromConfig(cliOptions.config),
3636
resolver:
37-
cliOptions.telemetry === 'runtime' ? RuntimeResolver.build() : (null as unknown as Resolver),
37+
cliOptions.telemetry === 'runtime' ? RuntimeResolver.build() : EmbroiderResolver.build(),
3838
};
3939
}
4040

transforms/no-implicit-this/helpers/resolver.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
// FIXME: Make these optional dependencies
12
import { Telemetry, getTelemetry } from './telemetry';
3+
import { Resolver as _EmbroiderResolver } from '@embroider/core';
4+
import { readFileSync } from 'node:fs';
5+
import { resolve } from 'node:path';
26

37
export default abstract class Resolver {
48
has(type: 'component' | 'helper' | 'ambiguous', name: string): boolean {
@@ -57,3 +61,46 @@ function populateInvokeables(telemetry: Telemetry): [components: string[], helpe
5761

5862
return [components, helpers];
5963
}
64+
65+
const EMBROIDER_COMPONENTS = '#embroider_compat/components';
66+
const EMBROIDER_HELPERS = '#embroider_compat/helpers';
67+
const EMBROIDER_AMBIGUOUS = '#embroider_compat/ambiguous';
68+
69+
export class EmbroiderResolver extends Resolver {
70+
static build(): EmbroiderResolver {
71+
// FIXME: Run build via execa ???
72+
const stage2Output = readFileSync('dist/.stage2-output', 'utf8');
73+
const resolver = new _EmbroiderResolver(
74+
JSON.parse(readFileSync(resolve(stage2Output, '.embroider/resolver.json'), 'utf8'))
75+
);
76+
return new EmbroiderResolver(resolver, resolve(stage2Output, 'app.js'));
77+
}
78+
79+
constructor(private _resolver: _EmbroiderResolver, private entryPoint: string) {
80+
super();
81+
}
82+
83+
override hasComponent(name: string): boolean {
84+
return this.resolve(`${EMBROIDER_COMPONENTS}/${name}`);
85+
}
86+
87+
override hasHelper(name: string): boolean {
88+
return this.resolve(`${EMBROIDER_HELPERS}/${name}`);
89+
}
90+
91+
override hasAmbiguous(name: string): boolean {
92+
return this.resolve(`${EMBROIDER_AMBIGUOUS}/${name}`);
93+
}
94+
95+
private resolve(specifier: string): boolean {
96+
console.log(`Resolving ${specifier}`);
97+
const resolution = this._resolver.nodeResolve(specifier, this.entryPoint);
98+
switch (resolution.type) {
99+
case 'real':
100+
case 'virtual':
101+
return true;
102+
case 'not_found':
103+
return false;
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)