Skip to content

Commit 89b99e3

Browse files
authored
Remove fs-extra dependency (#1302)
This PR removes the fs-extra dependency by implementing equivalent filesystem utilities using Node.js built-in modules. The change replaces fs-extra with custom utility functions that provide the same functionality while reducing external dependencies. Key changes: - Created a comprehensive utils module with filesystem operations equivalent to fs-extra - Updated all imports to use the new utility module instead of fs-extra - Removed fs-extra from package.json dependencies Fix: #1300
1 parent bf0944a commit 89b99e3

File tree

7 files changed

+185
-11
lines changed

7 files changed

+185
-11
lines changed

lib/utils.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,156 @@
1313
// limitations under the License.
1414

1515
const fs = require('fs');
16+
const fsPromises = require('fs/promises');
17+
const path = require('path');
18+
19+
/**
20+
* Ensure directory exists, create recursively if needed (async)
21+
* Replaces: fse.ensureDir() / fse.mkdirs()
22+
* @param {string} dirPath - Path to directory
23+
* @returns {Promise<void>}
24+
*/
25+
async function ensureDir(dirPath) {
26+
try {
27+
await fsPromises.mkdir(dirPath, { recursive: true });
28+
} catch (err) {
29+
// Ignore if directory already exists
30+
if (err.code !== 'EEXIST') throw err;
31+
}
32+
}
33+
34+
/**
35+
* Ensure directory exists, create recursively if needed (sync)
36+
* Replaces: fse.mkdirSync()
37+
* @param {string} dirPath - Path to directory
38+
*/
39+
function ensureDirSync(dirPath) {
40+
try {
41+
fs.mkdirSync(dirPath, { recursive: true });
42+
} catch (err) {
43+
// Ignore if directory already exists
44+
if (err.code !== 'EEXIST') throw err;
45+
}
46+
}
47+
48+
/**
49+
* Check if path exists (async)
50+
* Replaces: fse.exists()
51+
* @param {string} filePath - Path to check
52+
* @returns {Promise<boolean>}
53+
*/
54+
async function pathExists(filePath) {
55+
try {
56+
await fsPromises.access(filePath);
57+
return true;
58+
} catch {
59+
return false;
60+
}
61+
}
62+
63+
/**
64+
* Empty a directory (remove all contents but keep the directory)
65+
* Replaces: fse.emptyDir()
66+
* @param {string} dirPath - Path to directory
67+
* @returns {Promise<void>}
68+
*/
69+
async function emptyDir(dirPath) {
70+
try {
71+
const files = await fsPromises.readdir(dirPath);
72+
await Promise.all(
73+
files.map((file) =>
74+
fsPromises.rm(path.join(dirPath, file), {
75+
recursive: true,
76+
force: true,
77+
})
78+
)
79+
);
80+
} catch (err) {
81+
// Ignore if directory doesn't exist
82+
if (err.code !== 'ENOENT') throw err;
83+
}
84+
}
85+
86+
/**
87+
* Copy file or directory recursively
88+
* Replaces: fse.copy()
89+
* @param {string} src - Source path
90+
* @param {string} dest - Destination path
91+
* @param {object} options - Copy options
92+
* @returns {Promise<void>}
93+
*/
94+
async function copy(src, dest, options = {}) {
95+
const opts = {
96+
recursive: true,
97+
force: options.overwrite !== false,
98+
...options,
99+
};
100+
await fsPromises.cp(src, dest, opts);
101+
}
102+
103+
/**
104+
* Read and parse JSON file synchronously
105+
* Replaces: fse.readJsonSync()
106+
* @param {string} filePath - Path to JSON file
107+
* @param {object} options - Read options
108+
* @returns {any} Parsed JSON data
109+
*/
110+
function readJsonSync(filePath, options = {}) {
111+
const content = fs.readFileSync(filePath, options.encoding || 'utf8');
112+
return JSON.parse(content);
113+
}
114+
115+
/**
116+
* Remove file or directory (async)
117+
* Replaces: fse.remove()
118+
* @param {string} filePath - Path to remove
119+
* @returns {Promise<void>}
120+
*/
121+
async function remove(filePath) {
122+
try {
123+
await fsPromises.rm(filePath, { recursive: true, force: true });
124+
} catch (err) {
125+
// Ignore if path doesn't exist
126+
if (err.code !== 'ENOENT') throw err;
127+
}
128+
}
129+
130+
/**
131+
* Remove file or directory (sync)
132+
* Replaces: fse.removeSync()
133+
* @param {string} filePath - Path to remove
134+
*/
135+
function removeSync(filePath) {
136+
try {
137+
fs.rmSync(filePath, { recursive: true, force: true });
138+
} catch (err) {
139+
// Ignore if path doesn't exist
140+
if (err.code !== 'ENOENT') throw err;
141+
}
142+
}
143+
144+
/**
145+
* Write file with content (async)
146+
* Replaces: fse.writeFile()
147+
* @param {string} filePath - Path to file
148+
* @param {string|Buffer} data - Content to write
149+
* @param {object} options - Write options
150+
* @returns {Promise<void>}
151+
*/
152+
async function writeFile(filePath, data, options = {}) {
153+
await fsPromises.writeFile(filePath, data, options);
154+
}
155+
156+
/**
157+
* Create directory (async)
158+
* Replaces: fse.mkdir()
159+
* @param {string} dirPath - Path to directory
160+
* @param {object} options - mkdir options
161+
* @returns {Promise<void>}
162+
*/
163+
async function mkdir(dirPath, options = {}) {
164+
await fsPromises.mkdir(dirPath, options);
165+
}
16166

17167
/**
18168
* Detect Ubuntu codename from /etc/os-release
@@ -87,7 +237,26 @@ function isClose(a, b, rtol = 1e-9, atol = 0.0) {
87237

88238
return rtol >= relativeDiff;
89239
}
240+
90241
module.exports = {
242+
// General utilities
91243
detectUbuntuCodename,
92244
isClose,
245+
246+
// File system utilities (async)
247+
ensureDir,
248+
mkdirs: ensureDir, // Alias for fs-extra compatibility
249+
exists: pathExists, // Renamed to avoid conflict with deprecated fs.exists
250+
pathExists,
251+
emptyDir,
252+
copy,
253+
remove,
254+
writeFile,
255+
mkdir,
256+
257+
// File system utilities (sync)
258+
ensureDirSync,
259+
mkdirSync: ensureDirSync, // Alias for fs-extra compatibility
260+
removeSync,
261+
readJsonSync,
93262
};

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@
7878
"bindings": "^1.5.0",
7979
"compare-versions": "^6.1.1",
8080
"debug": "^4.4.0",
81-
"fs-extra": "^11.2.0",
8281
"json-bigint": "^1.0.0",
8382
"node-addon-api": "^8.3.1",
8483
"walk": "^2.3.15"

rosidl_convertor/idl_convertor.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414

1515
'use strict';
1616

17+
const fs = require('fs');
1718
const path = require('path');
18-
const fse = require('fs-extra');
19+
const fse = require('../lib/utils.js');
1920
const execFile = require('child_process').execFile;
2021
const pythonExecutable =
2122
require('../rosidl_parser/py_utils').getPythonExecutable('python3');
2223

2324
async function convertIDLToROS2IDL(pkgName, idlFilePath, outputDir) {
2425
const packagePath = path.join(outputDir, pkgName);
25-
if (!fse.existsSync(packagePath)) {
26+
if (!fs.existsSync(packagePath)) {
2627
fse.mkdirSync(packagePath);
2728
}
2829
return new Promise((resolve, reject) => {

rosidl_gen/generate_worker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
const fse = require('fs-extra');
15+
const fse = require('../lib/utils.js');
1616
const generateJSStructFromIDL = require('./idl_generator.js');
1717
const packages = require('./packages.js');
1818
const path = require('path');

rosidl_gen/idl_generator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const fse = require('fs-extra');
17+
const fse = require('../lib/utils.js');
1818
const path = require('path');
1919
const parser = require('../rosidl_parser/rosidl_parser.js');
2020
const actionMsgs = require('./action_msgs.js');

rosidl_gen/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
'use strict';
1616

17-
const fse = require('fs-extra');
17+
const fse = require('../lib/utils.js');
1818
const generateJSStructFromIDL = require('./idl_generator.js');
1919
const packages = require('./packages.js');
2020
const path = require('path');

scripts/run_test.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414

1515
'use strict';
1616

17-
const fs = require('fs-extra');
17+
const fs = require('fs');
18+
const utils = require('../lib/utils.js');
1819
const Mocha = require('mocha');
1920
const os = require('os');
2021
const path = require('path');
2122

22-
fs.remove(path.join(path.dirname(__dirname), 'generated'), (err) => {
23-
if (!err) {
23+
utils
24+
.remove(path.join(path.dirname(__dirname), 'generated'))
25+
.then(() => {
2426
let mocha = new Mocha();
2527
const testDir = path.join(__dirname, '../test/');
2628
// eslint-disable-next-line
@@ -45,5 +47,8 @@ fs.remove(path.join(path.dirname(__dirname), 'generated'), (err) => {
4547
process.exit(failures);
4648
});
4749
});
48-
}
49-
});
50+
})
51+
.catch((err) => {
52+
console.error('Failed to clean generated directory:', err);
53+
process.exit(1);
54+
});

0 commit comments

Comments
 (0)