Skip to content

Commit

Permalink
feat: Add overwrite option to source file and directory copy.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Dec 26, 2017
1 parent c726fff commit 0741180
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 12 deletions.
4 changes: 3 additions & 1 deletion docs/details/source-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ Copy a source file to a new file by specifying a new relative or absolute path:

```typescript
const newSourceFile = sourceFile.copy("newFileName.ts");
// this won't throw if a file exists at the specified path
const otherSourceFile = sourceFile.copy("other.ts", { overwrite: true });
```

Note that the file won't be written to the file system unless you save it.
Note that the file, in both these cases, won't be written to the file system unless you save it.

### Move

Expand Down
3 changes: 2 additions & 1 deletion docs/navigation/directories.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ Copy the directory to a new directory:
```
// ex. copies C:\MyProject\dir to C:\MyProject\newDir
directory.copy("../newDir");
directory.copy("../newDir", { overwrite: true }); // don't throw if it will overwrite a file
directory.copy("C:\\test"); // or absolute
```

Note that the directory and source files won't be created until calling save on them.
Note that the directory and source files, in all these cases, won't be created until calling save on them.

### Deleting

Expand Down
17 changes: 15 additions & 2 deletions src/compiler/file/SourceFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,23 @@ export class SourceFile extends SourceFileBase<ts.SourceFile> {
/**
* Copy this source file to a new file.
* @param filePath - A new file path. Can be relative to the original file or an absolute path.
* @param options - Options for copying.
*/
copy(filePath: string): SourceFile {
copy(filePath: string, options: { overwrite?: boolean; } = {}): SourceFile {
const {overwrite = false} = options;
const absoluteFilePath = FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePath, this.getDirectoryPath());
return this.global.compilerFactory.createSourceFileFromText(absoluteFilePath, this.getFullText());

if (overwrite)
return this.global.compilerFactory.createOrOverwriteSourceFileFromText(absoluteFilePath, this.getFullText());

try {
return this.global.compilerFactory.createSourceFileFromText(absoluteFilePath, this.getFullText());
} catch (err) {
if (err instanceof errors.InvalidOperationError)
throw new errors.InvalidOperationError(`Did you mean to provide the overwrite option? ` + err.message);
else
throw err;
}
}

/**
Expand Down
28 changes: 24 additions & 4 deletions src/factories/CompilerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,29 @@ export class CompilerFactory {
* Adds it to the cache.
* @param filePath - File path for the source file.
* @param sourceText - Text to create the source file with.
* @throws InvalidOperationError if the file exists.
*/
createSourceFileFromText(filePath: string, sourceText: string) {
filePath = FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePath);
if (this.containsSourceFileAtPath(filePath) || this.global.fileSystem.fileExistsSync(filePath))
throw new errors.InvalidOperationError(`A source file already exists at the provided file path: ${filePath}`);
const compilerSourceFile = ts.createSourceFile(filePath, sourceText, this.global.manipulationSettings.getScriptTarget(), true);
return this.getSourceFile(compilerSourceFile);
return this.getSourceFileFromText(filePath, sourceText);
}

/**
* Creates or overwrites a source file and text.
* Adds it to the cache.
* @param filePath - File path for the source file.
* @param sourceText - Text to create the source file with.
*/
createOrOverwriteSourceFileFromText(filePath: string, sourceText: string) {
filePath = FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePath);
const existingSourceFile = this.getSourceFileFromFilePath(filePath);
if (existingSourceFile != null) {
existingSourceFile.replaceWithText(sourceText);
return existingSourceFile;
}
return this.getSourceFileFromText(filePath, sourceText);
}

/**
Expand All @@ -110,8 +126,7 @@ export class CompilerFactory {
if (sourceFile == null) {
if (this.global.fileSystem.fileExistsSync(filePath)) {
Logger.log(`Loading file: ${filePath}`);
const compilerSourceFile = ts.createSourceFile(filePath, this.global.fileSystem.readFileSync(filePath), this.global.manipulationSettings.getScriptTarget(), true);
sourceFile = this.getSourceFile(compilerSourceFile);
sourceFile = this.getSourceFileFromText(filePath, this.global.fileSystem.readFileSync(filePath));
sourceFile.setIsSaved(true); // source files loaded from the disk are saved to start with
}

Expand Down Expand Up @@ -194,6 +209,11 @@ export class CompilerFactory {
return this.nodeCache.getOrCreate<compiler.Node<NodeType>>(compilerNode, () => createNode(compiler.Node));
}

private getSourceFileFromText(filePath: string, sourceText: string): compiler.SourceFile {
const compilerSourceFile = ts.createSourceFile(filePath, sourceText, this.global.manipulationSettings.getScriptTarget(), true);
return this.getSourceFile(compilerSourceFile);
}

/**
* Gets a wrapped source file from a compiler source file.
* @param sourceFile - Compiler source file.
Expand Down
7 changes: 4 additions & 3 deletions src/fileSystem/Directory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,16 +369,17 @@ export class Directory {
/**
* Copies a directory to a new directory.
* @param relativeOrAbsolutePath - The relative or absolute path to the new directory.
* @param options - Options.
* @returns The directory the copy was made to.
*/
copy(relativeOrAbsolutePath: string) {
copy(relativeOrAbsolutePath: string, options: { overwrite?: boolean; } = {}) {
const newPath = FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, relativeOrAbsolutePath, this.getPath());
const directory = this.global.compilerFactory.createOrAddDirectoryIfNotExists(newPath);

for (const sourceFile of this.getSourceFiles())
sourceFile.copy(FileUtils.pathJoin(newPath, sourceFile.getBaseName()));
sourceFile.copy(FileUtils.pathJoin(newPath, sourceFile.getBaseName()), options);
for (const childDir of this.getDirectories())
childDir.copy(FileUtils.pathJoin(newPath, childDir.getBaseName()));
childDir.copy(FileUtils.pathJoin(newPath, childDir.getBaseName()), options);

return directory;
}
Expand Down
18 changes: 17 additions & 1 deletion src/tests/compiler/file/sourceFileTests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {expect} from "chai";
import * as ts from "typescript";
import * as errors from "./../../../errors";
import {SourceFile, ImportDeclaration, ExportDeclaration, ExportAssignment, EmitResult, FormatCodeSettings, QuoteType,
FileSystemRefreshResult} from "./../../../compiler";
import {IndentationText, ManipulationSettings, NewLineKind} from "./../../../ManipulationSettings";
Expand All @@ -15,10 +16,25 @@ describe(nameof(SourceFile), () => {
const {sourceFile, tsSimpleAst} = getInfoFromText(fileText, { filePath: "Folder/File.ts" });
const relativeSourceFile = sourceFile.copy("../NewFolder/NewFile.ts");
const absoluteSourceFile = sourceFile.copy("/NewFile.ts");
const testFile = sourceFile.copy("/TestFile.ts");

it("should throw if the file already exists", () => {
expect(() => sourceFile.copy("/TestFile.ts")).to.throw(errors.InvalidOperationError,
"Did you mean to provide the overwrite option? A source file already exists at the provided file path: /TestFile.ts");
});

it("should overwrite if specifying to overwrite", () => {
const newText = "const t = 5;";
sourceFile.replaceWithText(newText);
const copiedFile = sourceFile.copy("/TestFile.ts", { overwrite: true });
expect(copiedFile).to.equal(testFile);
expect(copiedFile.getFullText()).to.equal(newText);
expect(testFile.getFullText()).to.equal(newText);
});

describe(nameof(tsSimpleAst), () => {
it("should include the copied source files", () => {
expect(tsSimpleAst.getSourceFiles().length).to.equal(3);
expect(tsSimpleAst.getSourceFiles().length).to.equal(4);
});
});

Expand Down
17 changes: 17 additions & 0 deletions src/tests/fileSystem/directoryTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,23 @@ describe(nameof(Directory), () => {
dir.createSourceFile("file.ts");
expect(() => dir.copy("../newDir")).to.not.throw();
});

it("should throw when copying a directory to an existing directory and a file exists in the other one", () => {
const ast = getAst([]);
const dir = ast.createDirectory("dir");
dir.createDirectory("subDir").createSourceFile("file.ts");
dir.createSourceFile("file.ts");
dir.copy("../newDir");
expect(() => dir.copy("../newDir")).to.throw();
});

it("should not throw when copying a directory to an existing directory with the overwrite option and a file exists in the other one", () => {
const ast = getAst([]);
const dir = ast.createDirectory("dir");
dir.createSourceFile("file.ts");
dir.copy("../newDir");
expect(() => dir.copy("../newDir", { overwrite: true })).to.not.throw();
});
});

describe(nameof<Directory>(d => d.delete), () => {
Expand Down

0 comments on commit 0741180

Please sign in to comment.