UNPKG

2.95 kBPlain TextView Raw
1import path from 'path';
2
3import { FileDescription, MutateDescription } from '@stryker-mutator/api/src/core';
4import { File } from '@stryker-mutator/instrumenter';
5import { I } from '@stryker-mutator/util';
6
7import { FileSystem } from './file-system.js';
8
9/**
10 * Represents a file inside the project under test.
11 * Has utility methods to help with copying it to the sandbox, or backing it up (when `--inPlace` is active)
12 *
13 * Assumes utf-8 as encoding when reading/writing content.
14 */
15export class ProjectFile implements FileDescription {
16 #currentContent: string | undefined;
17 #originalContent: string | undefined;
18 #relativePath: string;
19
20 constructor(private readonly fs: I<FileSystem>, private readonly name: string, public mutate: MutateDescription) {
21 this.#relativePath = path.relative(process.cwd(), this.name);
22 }
23
24 async #writeTo(to: string): Promise<void> {
25 if (this.#currentContent === undefined) {
26 await this.fs.copyFile(this.name, to);
27 } else {
28 await this.fs.writeFile(to, this.#currentContent, 'utf-8');
29 }
30 }
31
32 public setContent(content: string): void {
33 this.#currentContent = content;
34 }
35
36 public async toInstrumenterFile(): Promise<File> {
37 return {
38 content: await this.readContent(),
39 mutate: this.mutate,
40 name: this.name,
41 };
42 }
43
44 public async readContent(): Promise<string> {
45 if (this.#currentContent === undefined) {
46 this.#currentContent = await this.readOriginal();
47 }
48 return this.#currentContent;
49 }
50
51 public async readOriginal(): Promise<string> {
52 if (this.#originalContent === undefined) {
53 this.#originalContent = await this.fs.readFile(this.name, 'utf-8');
54 if (this.#currentContent === undefined) {
55 this.#currentContent = this.#originalContent;
56 }
57 }
58 return this.#originalContent;
59 }
60
61 public async writeInPlace(): Promise<void> {
62 if (this.#currentContent !== undefined && this.hasChanges) {
63 await this.fs.writeFile(this.name, this.#currentContent, 'utf-8');
64 }
65 }
66
67 public async writeToSandbox(sandboxDir: string): Promise<string> {
68 const folderName = path.join(sandboxDir, path.dirname(this.#relativePath));
69 const targetFileName = path.join(folderName, path.basename(this.#relativePath));
70 await this.fs.mkdir(path.dirname(targetFileName), { recursive: true });
71 await this.#writeTo(targetFileName);
72 return targetFileName;
73 }
74
75 public async backupTo(backupDir: string): Promise<string> {
76 const backupFileName = path.join(backupDir, this.#relativePath);
77 await this.fs.mkdir(path.dirname(backupFileName), { recursive: true });
78 if (this.#originalContent === undefined) {
79 await this.fs.copyFile(this.name, backupFileName);
80 } else {
81 await this.fs.writeFile(backupFileName, this.#originalContent);
82 }
83 return backupFileName;
84 }
85
86 public get hasChanges(): boolean {
87 return this.#currentContent !== this.#originalContent;
88 }
89}