Skip to content

Commit c54e20a

Browse files
johncrimahnpnl
andauthored
fix(compiler): update SourceFile with correct file content (#765)
Previously SourceFile.text was the old contents of the file - however the file was during startup. This change updates the SourceFile text so that emit() receives the changed file contents. Closes #764 Co-authored-by: Ahn <[email protected]>
1 parent 2bbc45d commit c54e20a

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

src/__tests__/__snapshots__/ng-jest-compiler.spec.ts.snap

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,50 @@ export { AppComponent };
2020
//# "
2121
`;
2222

23+
exports[`NgJestCompiler with isolatedModule false should compile new code when file changes: from hasErrorFileContent 1`] = `
24+
"\\"use strict\\";
25+
Object.defineProperty(exports, \\"__esModule\\", { value: true });
26+
exports.AppComponent = void 0;
27+
const tslib_1 = require(\\"tslib\\");
28+
const core_1 = require(\\"@angular/core\\");
29+
let = class {
30+
constructor() {
31+
this. = ;
32+
}
33+
};
34+
= tslib_1.__decorate([
35+
core_1.Component({
36+
selector: 'app-root',
37+
template: require(\\"./app.component.html\\"),
38+
styles: []
39+
})
40+
], );
41+
exports.AppComponent = ;
42+
//# "
43+
`;
44+
45+
exports[`NgJestCompiler with isolatedModule false should compile new code when file changes: from noErrorFileContent 1`] = `
46+
"\\"use strict\\";
47+
Object.defineProperty(exports, \\"__esModule\\", { value: true });
48+
exports.AppComponent = void 0;
49+
const tslib_1 = require(\\"tslib\\");
50+
const core_1 = require(\\"@angular/core\\");
51+
let AppComponent = class AppComponent {
52+
constructor() {
53+
this.title = 'test-app-v10';
54+
}
55+
};
56+
AppComponent = tslib_1.__decorate([
57+
core_1.Component({
58+
selector: 'app-root',
59+
template: require(\\"./app.component.html\\"),
60+
styles: []
61+
})
62+
], AppComponent);
63+
exports.AppComponent = AppComponent;
64+
//# "
65+
`;
66+
2367
exports[`NgJestCompiler with isolatedModule false should throw diagnostics error for new file which is: known by Program 1`] = `"src/__tests__/__mocks__/foo.component.ts(8,3): error TS2322: Type 'string' is not assignable to type 'number'."`;
2468

2569
exports[`NgJestCompiler with isolatedModule false should throw diagnostics error for new file which is: not known by Program 1`] = `"src/__tests__/__mocks__/foo.component.ts(8,3): error TS2322: Type 'string' is not assignable to type 'number'."`;

src/__tests__/ng-jest-compiler.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,24 @@ describe('NgJestCompiler', () => {
123123
},
124124
);
125125

126+
test('should compile new code when file changes', () => {
127+
const ngJestConfig = new NgJestConfig(jestCfgStub);
128+
const compiler = new NgJestCompiler(ngJestConfig, new Map());
129+
130+
// Compile the same file with 2 versions of content: noErrorFileContent and hasErrorFileContent
131+
const fileName = noErrorFileName;
132+
const emittedResult1 = compiler.getCompiledOutput(fileName, noErrorFileContent, true);
133+
expect(emittedResult1.substring(0, emittedResult1.indexOf(SOURCE_MAPPING_PREFIX))).toMatchSnapshot(
134+
'from noErrorFileContent',
135+
);
136+
const emittedResult2 = compiler.getCompiledOutput(fileName, hasErrorFileContent, true);
137+
expect(emittedResult2.substring(0, emittedResult2.indexOf(SOURCE_MAPPING_PREFIX))).toMatchSnapshot(
138+
'from hasErrorFileContent',
139+
);
140+
141+
expect(emittedResult1).not.toEqual(emittedResult2);
142+
});
143+
126144
test('should compile codes with useESM true', () => {
127145
const ngJestConfig = new NgJestConfig({
128146
...jestCfgStub,

src/compiler/ng-jest-compiler.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,27 @@ export class NgJestCompiler implements CompilerInstance {
7070
esModuleInterop,
7171
module: moduleKind,
7272
};
73+
7374
if (this._program) {
74-
const allDiagnostics: ts.Diagnostic[] = [];
75-
if (!this._rootNames.includes(fileName)) {
76-
this._logger.debug({ fileName }, 'getCompiledOutput: update memory host, rootFiles and Program');
75+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
76+
this._tsHost!.updateMemoryHost(fileName, fileContent);
7777

78+
let sourceFile: ts.SourceFile | undefined;
79+
if (!this._rootNames.includes(fileName)) {
80+
this._logger.debug({ fileName }, 'getCompiledOutput: adding file to rootNames and updating Program');
7881
this._rootNames = [...this._rootNames, fileName];
79-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
80-
this._tsHost!.updateMemoryHost(fileName, fileContent);
8182
this._createOrUpdateProgram();
83+
sourceFile = this._program.getSourceFile(fileName);
84+
} else {
85+
sourceFile = this._program.getSourceFile(fileName);
86+
if (sourceFile) {
87+
const replaceSpan: ts.TextSpan = { start: 0, length: sourceFile.text.length };
88+
sourceFile.update(fileContent, { span: replaceSpan, newLength: fileContent.length });
89+
}
8290
}
8391

8492
this._logger.debug({ fileName }, 'getCompiledOutput: compiling using Program');
8593

86-
const sourceFile = this._program.getSourceFile(fileName);
8794
const emitResult = this._program.emit(sourceFile, undefined, undefined, undefined, {
8895
...customTransformers,
8996
before: [
@@ -98,8 +105,10 @@ export class NgJestCompiler implements CompilerInstance {
98105
replaceResources(this.isAppPath, this._program.getTypeChecker),
99106
],
100107
});
108+
101109
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
102110
const compiledOutput: [string, string] = this._tsHost!.getEmittedResult();
111+
const allDiagnostics: ts.Diagnostic[] = [];
103112
if (this.ngJestConfig.shouldReportDiagnostics(fileName)) {
104113
this._logger.debug({ fileName }, 'getCompiledOutput: getting diagnostics');
105114

0 commit comments

Comments
 (0)