-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathupdate-files.ts
105 lines (87 loc) · 3.05 KB
/
update-files.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import * as path from "path";
import { readJsonFile, readTextFile, writeJsonFile, writeTextFile } from "./fs";
import { isManifest } from "./manifest";
import { Operation } from "./operation";
import { ProgressEvent } from "./types/version-bump-progress";
/**
* Updates the version number in the specified files.
*/
export async function updateFiles(operation: Operation): Promise<Operation> {
let { files } = operation.options;
for (let relPath of files) {
let modified = await updateFile(relPath, operation);
if (modified) {
operation.update({
event: ProgressEvent.FileUpdated,
updatedFiles: operation.state.updatedFiles.concat(relPath),
});
}
else {
operation.update({
event: ProgressEvent.FileSkipped,
skippedFiles: operation.state.skippedFiles.concat(relPath),
});
}
}
return operation;
}
/**
* Updates the version number in the specified file.
*
* @returns - `true` if the file was actually modified
*/
async function updateFile(relPath: string, operation: Operation): Promise<boolean> {
let name = path.basename(relPath).trim().toLowerCase();
switch (name) {
case "package.json":
case "package-lock.json":
case "bower.json":
case "component.json":
return updateManifestFile(relPath, operation);
default:
return updateTextFile(relPath, operation);
}
}
/**
* Updates the version number in the specified JSON manifest file.
*
* NOTE: Unlike text files, this is NOT a global find-and-replace. It _specifically_ sets
* the top-level `version` property.
*
* @returns - `true` if the file was actually modified
*/
async function updateManifestFile(relPath: string, operation: Operation): Promise<boolean> {
let { cwd } = operation.options;
let { newVersion } = operation.state;
let modified = false;
let file = await readJsonFile(relPath, cwd);
if (isManifest(file.data) && file.data.version !== newVersion) {
file.data.version = newVersion;
await writeJsonFile(file);
modified = true;
}
return modified;
}
/**
* Updates all occurrences of the version number in the specified text file.
*
* @returns - `true` if the file was actually modified
*/
async function updateTextFile(relPath: string, operation: Operation): Promise<boolean> {
let { cwd } = operation.options;
let { oldVersion, newVersion } = operation.state;
let modified = false;
let file = await readTextFile(relPath, cwd);
// Only update the file if it contains at least one occurrence of the old version
if (file.data.includes(oldVersion)) {
// Escape all non-alphanumeric characters in the version
let sanitizedVersion = oldVersion.replace(/(\W)/g, "\\$1");
// Replace occurrences of the old version number that are surrounded by word boundaries.
// This ensures that it matches "1.23.456" or "v1.23.456", but not "321.23.456".
let replacePattern = new RegExp("(\\b|v)" + sanitizedVersion + "\\b", "g");
file.data = file.data.replace(replacePattern, "$1" + newVersion);
await writeTextFile(file);
return true;
}
return modified;
}