Skip to content

Commit

Permalink
Merge pull request #1882 from embroider-build/audit-refactor
Browse files Browse the repository at this point in the history
Splitting reusable module visitor out of Audit
  • Loading branch information
mansona authored Apr 30, 2024
2 parents 3d20631 + 81946a0 commit 4c21dd5
Show file tree
Hide file tree
Showing 8 changed files with 585 additions and 382 deletions.
459 changes: 103 additions & 356 deletions packages/compat/src/audit.ts

Large diffs are not rendered by default.

407 changes: 407 additions & 0 deletions packages/compat/src/module-visitor.ts

Large diffs are not rendered by default.

46 changes: 34 additions & 12 deletions packages/compat/tests/audit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { AppMeta } from '@embroider/core';
import { throwOnWarnings } from '@embroider/core';
import merge from 'lodash/merge';
import fromPairs from 'lodash/fromPairs';
import type { Finding } from '../src/audit';
import { Audit } from '../src/audit';
import type { CompatResolverOptions } from '../src/resolver-transform';
import type { TransformOptions } from '@babel/core';
Expand Down Expand Up @@ -223,7 +222,11 @@ describe('audit', function () {
});
let result = await audit();
expect(result.findings).toEqual([]);
let exports = result.modules['./app.js'].exports;
let appModule = result.modules['./app.js'];
if (appModule.type !== 'complete') {
throw new Error('./app.js module did not parse or resolve correctly');
}
let exports = appModule.exports;
expect(exports).toContain('a');
expect(exports).toContain('b');
expect(exports).toContain('c');
Expand Down Expand Up @@ -270,17 +273,21 @@ describe('audit', function () {

let result = await audit();
expect(result.findings).toEqual([]);
let exports = result.modules['./app.js'].exports;
let appModule = result.modules['./app.js'];
if (appModule.type !== 'complete') {
throw new Error('./app.js module did not parse or resolve correctly');
}
let exports = appModule.exports;
expect(exports).toContain('a');
expect(exports).toContain('b');
expect(exports).not.toContain('thing');
expect(exports).toContain('c');
expect(exports).toContain('alpha');
expect(exports).toContain('beta');
expect(exports).toContain('libC');
expect(result.modules['./app.js'].imports.length).toBe(3);
let imports = fromPairs(result.modules['./app.js'].imports.map(imp => [imp.source, imp.specifiers]));
expect(imports).toEqual({
expect(appModule.imports.length).toBe(3);
let imports = fromPairs(appModule.imports.map(imp => [imp.source, imp.specifiers]));
expect(withoutCodeFrames(imports)).toEqual({
'./lib-a': [
{ name: 'default', local: null },
{ name: 'b', local: null },
Expand Down Expand Up @@ -397,10 +404,25 @@ describe('audit', function () {
});
});

function withoutCodeFrames(findings: Finding[]): Finding[] {
return findings.map(f => {
let result = Object.assign({}, f);
delete result.codeFrame;
return result;
});
function withoutCodeFrames<T extends { codeFrameIndex?: any }>(modules: Record<string, T[]>): Record<string, T[]>;
function withoutCodeFrames<T extends { codeFrame?: any }>(findings: T[]): T[];
function withoutCodeFrames<T extends { codeFrameIndex?: any }, U extends { codeFrame?: any }>(
input: Record<string, T[]> | U[]
): Record<string, T[]> | U[] {
if (Array.isArray(input)) {
return input.map(f => {
let result = Object.assign({}, f);
delete result.codeFrame;
return result;
});
}
const result: Record<string, T[]> = {};

const knownInput = input;

for (let item in knownInput) {
result[item] = knownInput[item].map(i => ({ ...i, codeFrameIndex: undefined }));
}

return result;
}
27 changes: 27 additions & 0 deletions test-packages/support/audit-assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ export class ExpectModule {
this.emitMissingModule();
return;
}
if (this.module.type === 'unparseable') {
this.emitUnparsableModule(message);
return;
}
const result = fn(this.module.content);
this.expectAudit.assert.pushResult({
result,
Expand All @@ -123,11 +127,24 @@ export class ExpectModule {
});
}

private emitUnparsableModule(message?: string) {
this.expectAudit.assert.pushResult({
result: false,
actual: `${this.inputName} failed to parse`,
expected: true,
message: `${this.inputName} failed to parse${message ? `: (${message})` : ''}`,
});
}

codeEquals(expectedSource: string) {
if (!this.module) {
this.emitMissingModule();
return;
}
if (this.module.type === 'unparseable') {
this.emitUnparsableModule();
return;
}
this.expectAudit.assert.codeEqual(this.module.content, expectedSource);
}

Expand All @@ -136,6 +153,10 @@ export class ExpectModule {
this.emitMissingModule();
return;
}
if (this.module.type === 'unparseable') {
this.emitUnparsableModule();
return;
}
this.expectAudit.assert.codeContains(this.module.content, expectedSource);
}

Expand All @@ -144,6 +165,12 @@ export class ExpectModule {
this.emitMissingModule();
return new EmptyExpectResolution();
}

if (this.module.type === 'unparseable') {
this.emitUnparsableModule();
return new EmptyExpectResolution();
}

if (!(specifier in this.module.resolutions)) {
this.expectAudit.assert.pushResult({
result: false,
Expand Down
2 changes: 1 addition & 1 deletion tests/scenarios/compat-exclude-dot-files-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ appScenarios
// but not be picked up in the entrypoint
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/app-template.js')
.resolves('/assets/app-template.js')
.toModule()
.withContents(content => {
assert.notOk(/app-template\/\.foobar/.test(content), '.foobar is not in the entrypoint');
Expand Down
2 changes: 1 addition & 1 deletion tests/scenarios/compat-renaming-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ appScenarios
test('renamed modules keep their classic runtime name when used as implicit-modules', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/app-template.js')
.resolves('/assets/app-template.js')
.toModule()
.resolves('./-embroider-implicit-modules.js')
.toModule()
Expand Down
22 changes: 11 additions & 11 deletions tests/scenarios/compat-stage2-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ stage2Scenarios
// check that the app trees with in repo addon are combined correctly
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
//TODO investigate removing this @embroider-dep
.resolves('my-app/service/in-repo.js')
Expand All @@ -142,7 +142,7 @@ stage2Scenarios
// secondary in-repo-addon was correctly detected and activated
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
//TODO investigate removing this @embroider-dep
.resolves('my-app/services/secondary.js')
Expand Down Expand Up @@ -209,7 +209,7 @@ stage2Scenarios
test('verifies that the correct lexigraphically sorted addons win', function () {
let expectModule = expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule();
expectModule.resolves('my-app/service/in-repo.js').to('./lib/in-repo-b/_app_/service/in-repo.js');
expectModule.resolves('my-app/service/addon.js').to('./node_modules/dep-b/_app_/service/addon.js');
Expand All @@ -219,7 +219,7 @@ stage2Scenarios
test('addons declared as dependencies should win over devDependencies', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.resolves('my-app/service/dep-wins-over-dev.js')
.to('./node_modules/dep-b/_app_/service/dep-wins-over-dev.js');
Expand All @@ -228,7 +228,7 @@ stage2Scenarios
test('in repo addons declared win over dependencies', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.resolves('my-app/service/in-repo-over-deps.js')
.to('./lib/in-repo-a/_app_/service/in-repo-over-deps.js');
Expand All @@ -237,7 +237,7 @@ stage2Scenarios
test('ordering with before specified', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.resolves('my-app/service/test-before.js')
.to('./node_modules/dev-d/_app_/service/test-before.js');
Expand All @@ -246,7 +246,7 @@ stage2Scenarios
test('ordering with after specified', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.resolves('my-app/service/test-after.js')
.to('./node_modules/dev-b/_app_/service/test-after.js');
Expand Down Expand Up @@ -675,7 +675,7 @@ stage2Scenarios
test('non-static other paths are included in the entrypoint', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule().codeContains(`d("my-app/non-static-dir/another-library", function () {
return i("my-app/non-static-dir/another-library.js");
});`);
Expand All @@ -684,7 +684,7 @@ stage2Scenarios
test('static other paths are not included in the entrypoint', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.withContents(content => {
return !/my-app\/static-dir\/my-library\.js"/.test(content);
Expand All @@ -694,7 +694,7 @@ stage2Scenarios
test('top-level static other paths are not included in the entrypoint', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.withContents(content => {
return !content.includes('my-app/top-level-static.js');
Expand All @@ -704,7 +704,7 @@ stage2Scenarios
test('staticAppPaths do not match partial path segments', function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule()
.withContents(content => {
return content.includes('my-app/static-dir-not-really/something.js');
Expand Down
2 changes: 1 addition & 1 deletion tests/scenarios/compat-template-colocation-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ scenarios
test(`app's colocated components are implicitly included correctly`, function () {
expectAudit
.module('./node_modules/.embroider/rewritten-app/index.html')
.resolves('./assets/my-app.js')
.resolves('/assets/my-app.js')
.toModule().codeContains(`d("my-app/components/has-colocated-template", function () {
return i("my-app/components/has-colocated-template.js");
});`);
Expand Down

0 comments on commit 4c21dd5

Please sign in to comment.