Skip to content

Commit 29594e4

Browse files
committed
refactor(cli): move file operations to ProjectFilesManager class
1 parent e405de5 commit 29594e4

File tree

4 files changed

+165
-70
lines changed

4 files changed

+165
-70
lines changed

cli/clone-repo.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const getLatestRelease = async () => {
1616
}
1717
};
1818

19-
const cloneLastTemplateRelease = async (projectName) => {
19+
const cloneLatestTemplateRelease = async (projectName) => {
2020
consola.start('Extracting last release number 👀');
2121
const latest_release = await getLatestRelease();
2222
consola.info(`Using Rootstrap's Template ${latest_release}`);
@@ -31,5 +31,5 @@ const cloneLastTemplateRelease = async (projectName) => {
3131
};
3232

3333
module.exports = {
34-
cloneLastTemplateRelease,
34+
cloneLatestTemplateRelease,
3535
};

cli/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
const { consola } = require('consola');
44
const { showMoreDetails } = require('./utils.js');
5-
const { cloneLastTemplateRelease } = require('./clone-repo.js');
6-
const { setupProject, installDeps } = require('./setup-project.js');
5+
const { cloneLatestTemplateRelease } = require('./clone-repo.js');
6+
const { setupProject, installDependencies } = require('./setup-project.js');
77
const pkg = require('./package.json');
88

99
const { name: packageName } = pkg;
@@ -18,14 +18,14 @@ const createRootstrapApp = async () => {
1818
);
1919
process.exit(1);
2020
}
21-
// clone the last release of the template from github
22-
await cloneLastTemplateRelease(projectName);
21+
// clone the latest release of the template from github
22+
await cloneLatestTemplateRelease(projectName);
2323

24-
// setup the project: remove unnecessary files, update package.json infos, name and set version to 0.0.1 + add initial version to osMetadata
24+
// setup the project
2525
await setupProject(projectName);
2626

2727
// install project dependencies using pnpm
28-
await installDeps(projectName);
28+
await installDependencies(projectName);
2929

3030
// show instructions to run the project + link to the documentation
3131
showMoreDetails(projectName);

cli/project-files-manager.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
const fs = require('fs-extra');
2+
const path = require('path');
3+
4+
class ProjectFilesManager {
5+
#projectName;
6+
7+
constructor(
8+
/**
9+
* @type {string}
10+
*/
11+
projectName
12+
) {
13+
this.#projectName = projectName;
14+
}
15+
16+
static withProjectName(
17+
/**
18+
* @type {string}
19+
*/
20+
projectName
21+
) {
22+
return new this(projectName);
23+
}
24+
25+
getAbsoluteFilePath(
26+
/**
27+
* A file path relative to project's root path
28+
* @type {string}
29+
*/
30+
relativeFilePath
31+
) {
32+
return path.join(process.cwd(), `${this.#projectName}/${relativeFilePath}`);
33+
}
34+
35+
removeFiles(
36+
/**
37+
* An array of file paths relative to project's root path
38+
* @type {Array<string>}
39+
*/
40+
files
41+
) {
42+
files.forEach((fileName) => {
43+
const absoluteFilePath = this.getAbsoluteFilePath(fileName);
44+
45+
fs.removeSync(absoluteFilePath);
46+
});
47+
}
48+
49+
renameFiles(
50+
/**
51+
* An array of objects containing the old and the new file names
52+
* relative to project's root path
53+
*
54+
* @type {Array<{
55+
* oldFileName: string;
56+
* newFileName: string;
57+
* }>}
58+
*/
59+
files
60+
) {
61+
files.forEach(({ oldFileName, newFileName }) => {
62+
const oldAbsoluteFilePath = this.getAbsoluteFilePath(oldFileName);
63+
const newAbsoluteFilePath = this.getAbsoluteFilePath(newFileName);
64+
65+
fs.renameSync(oldAbsoluteFilePath, newAbsoluteFilePath);
66+
});
67+
}
68+
69+
replaceFilesContent(
70+
/**
71+
* An array of objects containing the file name relative to project's
72+
* root path and the replacement patterns to be applied
73+
*
74+
* @type {Array<{
75+
* fileName: string;
76+
* replacements: Array<{
77+
* searchValue: string;
78+
* replaceValue: string;
79+
* }>
80+
* }>}
81+
*/
82+
files
83+
) {
84+
files.forEach(({ fileName, replacements }) => {
85+
const absoluteFilePath = this.getAbsoluteFilePath(fileName);
86+
87+
const contents = fs.readFileSync(absoluteFilePath, {
88+
encoding: 'utf-8',
89+
});
90+
91+
let replaced = contents;
92+
93+
replacements.forEach(({ searchValue, replaceValue }) => {
94+
replaced = replaced.replace(searchValue, replaceValue);
95+
});
96+
97+
fs.writeFileSync(absoluteFilePath, replaced, { spaces: 2 });
98+
});
99+
}
100+
}
101+
102+
module.exports = ProjectFilesManager;

cli/setup-project.js

Lines changed: 55 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,34 @@ const {
66
} = require('./utils.js');
77
const { consola } = require('consola');
88
const fs = require('fs-extra');
9-
const path = require('path');
9+
const ProjectFilesManager = require('./project-files-manager.js');
1010

11-
const initGit = async (projectName) => {
11+
/**
12+
* @type {ProjectFilesManager}
13+
*/
14+
let projectFilesManager;
15+
16+
const initializeProjectRepository = async (projectName) => {
1217
await execShellCommand(`cd ${projectName} && git init && cd ..`);
1318
};
1419

15-
const installDeps = async (projectName) => {
20+
const installDependencies = async (projectName) => {
1621
await runCommand(`cd ${projectName} && pnpm install`, {
1722
loading: 'Installing project dependencies',
1823
success: 'Dependencies installed',
1924
error: 'Failed to install dependencies, Make sure you have pnpm installed',
2025
});
2126
};
2227

23-
// remove unnecessary files and directories
24-
const removeFiles = (projectName) => {
25-
const FILES_TO_REMOVE = ['.git', 'README.md', 'docs', 'cli', 'LICENSE'];
26-
27-
FILES_TO_REMOVE.forEach((file) => {
28-
fs.removeSync(path.join(process.cwd(), `${projectName}/${file}`));
29-
});
28+
const removeUnrelatedFiles = () => {
29+
projectFilesManager.removeFiles(['.git', 'README.md', 'docs', 'cli', 'LICENSE']);
3030
};
3131

3232
// Update package.json infos, name and set version to 0.0.1 + add initial version to osMetadata
33-
const updatePackageInfos = async (projectName) => {
34-
const packageJsonPath = path.join(
35-
process.cwd(),
36-
`${projectName}/package.json`
37-
);
33+
const updatePackageJson = async (projectName) => {
34+
const packageJsonPath =
35+
projectFilesManager.getAbsoluteFilePath('package.json');
36+
3837
const packageJson = fs.readJsonSync(packageJsonPath);
3938
packageJson.osMetadata = { initVersion: packageJson.version };
4039
packageJson.version = '0.0.1';
@@ -53,20 +52,30 @@ const updatePackageInfos = async (projectName) => {
5352
};
5453

5554
const updateProjectConfig = async (projectName) => {
56-
const configPath = path.join(process.cwd(), `${projectName}/env.js`);
57-
const contents = fs.readFileSync(configPath, {
58-
encoding: 'utf-8',
59-
});
60-
const replaced = contents
61-
.replace(/RootstrapApp/gi, projectName)
62-
.replace(/com.rootstrap/gi, `com.${projectName.toLowerCase()}`)
63-
.replace(/rootstrap/gi, 'expo-owner');
64-
65-
fs.writeFileSync(configPath, replaced, { spaces: 2 });
55+
projectFilesManager.replaceFilesContent([
56+
{
57+
fileName: 'env.js',
58+
replacements: [
59+
{
60+
searchValue: /RootstrapApp/gi,
61+
replaceValue: projectName,
62+
},
63+
{
64+
searchValue: /com.rootstrap/gi,
65+
replaceValue: `com.${projectName.toLowerCase()}`,
66+
},
67+
{
68+
searchValue: /rsdevs/gi,
69+
replaceValue: 'expo-owner',
70+
},
71+
],
72+
},
73+
]);
6674
};
6775

6876
const updateGitHubWorkflows = (projectName) => {
69-
const WORKFLOW_FILES = [
77+
// Update useful workflows
78+
projectFilesManager.replaceFilesContent([
7079
{
7180
fileName: '.github/workflows/upstream-to-pr.yml',
7281
replacements: [
@@ -92,59 +101,43 @@ const updateGitHubWorkflows = (projectName) => {
92101
replaceValue: 'Run App release',
93102
},
94103
{
95-
searchValue: /^\s*environment:\s*\n\s*name:\s*template\s*\n\s*url:\s*.+\s*\n/m,
104+
searchValue:
105+
/^\s*environment:\s*\n\s*name:\s*template\s*\n\s*url:\s*.+\s*\n/m,
96106
replaceValue: '',
97107
},
98108
],
99109
},
100-
];
110+
]);
101111

102-
WORKFLOW_FILES.forEach(({ fileName, replacements }) => {
103-
const workflowPath = path.join(process.cwd(), `${projectName}/${fileName}`);
104-
105-
const contents = fs.readFileSync(workflowPath, {
106-
encoding: 'utf-8',
107-
});
108-
109-
let replaced = contents;
110-
111-
replacements.forEach(({ searchValue, replaceValue }) => {
112-
replaced = replaced.replace(searchValue, replaceValue);
113-
});
114-
115-
fs.writeFileSync(workflowPath, replaced, { spaces: 2 });
116-
});
112+
projectFilesManager.renameFiles([
113+
{
114+
oldFileName: '.github/workflows/new-template-version.yml',
115+
newFileName: '.github/workflows/new-app-version.yml',
116+
},
117+
]);
117118
};
118119

119-
const renameFiles = (projectName) => {
120-
const FILES_TO_RENAME = [
120+
const updateProjectReadme = () => {
121+
projectFilesManager.renameFiles([
121122
{
122123
oldFileName: 'README-project.md',
123124
newFileName: 'README.md',
124125
},
125-
{
126-
oldFileName: '.github/workflows/new-template-version.yml',
127-
newFileName: '.github/workflows/new-app-version.yml',
128-
},
129-
];
130-
131-
FILES_TO_RENAME.forEach(({ oldFileName, newFileName }) => {
132-
fs.renameSync(
133-
path.join(process.cwd(), `${projectName}/${oldFileName}`),
134-
path.join(process.cwd(), `${projectName}/${newFileName}`)
135-
);
136-
});
126+
]);
137127
};
138128

139129
const setupProject = async (projectName) => {
140130
consola.start(`Clean up and setup your project 🧹`);
131+
132+
projectFilesManager = ProjectFilesManager.withProjectName(projectName);
133+
141134
try {
142-
removeFiles(projectName);
143-
await initGit(projectName);
144-
updatePackageInfos(projectName);
135+
removeUnrelatedFiles();
136+
await initializeProjectRepository(projectName);
137+
updatePackageJson(projectName);
145138
updateProjectConfig(projectName);
146139
updateGitHubWorkflows(projectName);
147-
renameFiles(projectName);
140+
updateProjectReadme();
148141
consola.success(`Clean up and setup your project 🧹`);
149142
} catch (error) {
150143
consola.error(`Failed to clean up project folder`, error);
@@ -154,5 +147,5 @@ const setupProject = async (projectName) => {
154147

155148
module.exports = {
156149
setupProject,
157-
installDeps,
150+
installDependencies,
158151
};

0 commit comments

Comments
 (0)