From 23a34c1a07fea480c16bbe571066f6c3d51bac2b Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 9 Mar 2022 17:50:33 +0800 Subject: [PATCH] refactor: prefer fs.outputFile to ensureDir + writeFile (#6880) * refactor: prefer fs.outputFile to ensureDir + writeFile * fix test * fix --- .../__snapshots__/migration.test.ts.snap | 65 ++++++------------- .../src/__tests__/migration.test.ts | 4 +- packages/docusaurus-migrate/src/index.ts | 25 +++---- .../src/__tests__/writeRedirectFiles.test.ts | 3 +- .../src/writeRedirectFiles.ts | 3 +- .../src/feed.ts | 4 +- .../src/__tests__/cli.test.ts | 12 +--- .../docusaurus-plugin-content-docs/src/cli.ts | 6 +- .../docusaurus-theme-translations/update.js | 2 +- .../src/__tests__/emitUtils.test.ts | 2 +- .../src/__tests__/jsUtils.test.ts | 18 ++--- packages/docusaurus-utils/src/emitUtils.ts | 6 +- .../src/commands/swizzle/actions.ts | 3 +- .../__tests__/translationsExtractor.test.ts | 15 ++--- .../src/server/translations/translations.ts | 6 +- 15 files changed, 66 insertions(+), 108 deletions(-) diff --git a/packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap b/packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap index b217085727..b5be0f1ead 100644 --- a/packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap +++ b/packages/docusaurus-migrate/src/__tests__/__snapshots__/migration.test.ts.snap @@ -6,6 +6,10 @@ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/blog", "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/blog", ], + Array [ + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/pages/en", + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages", + ], Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/complex_website/website/static", "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/static", @@ -16,10 +20,7 @@ Array [ exports[`migration test complex website: mkdirp 1`] = ` Array [ Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/css", - ], - Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages/", + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages", ], ] `; @@ -179,16 +180,6 @@ Array [ } ", ], - Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_complex_site/src/pages/index.js", - "import Layout from \\"@theme/Layout\\"; - import React from \\"react\\"; - - export default () => { - return ; - }; - ", - ], ] `; @@ -198,6 +189,10 @@ Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/blog", "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/blog", ], + Array [ + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/pages/en", + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages", + ], Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/missing_version_website/website/static", "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/static", @@ -208,10 +203,7 @@ Array [ exports[`migration test missing versions: mkdirp 1`] = ` Array [ Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/css", - ], - Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages/", + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages", ], ] `; @@ -371,21 +363,15 @@ Array [ } ", ], - Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_missing_version_site/src/pages/index.js", - "import Layout from \\"@theme/Layout\\"; - import React from \\"react\\"; - - export default () => { - return ; - }; - ", - ], ] `; exports[`migration test simple website: copy 1`] = ` Array [ + Array [ + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/website/pages/en", + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages", + ], Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/website/static", "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/static", @@ -396,10 +382,7 @@ Array [ exports[`migration test simple website: mkdirp 1`] = ` Array [ Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/css", - ], - Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages/", + "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages", ], ] `; @@ -560,24 +543,14 @@ Array [ } ", ], - Array [ - "/packages/docusaurus-migrate/src/__tests__/__fixtures__/migrated_simple_site/src/pages/index.js", - "import Layout from \\"@theme/Layout\\"; - import React from \\"react\\"; - - export default () => { - return ; - }; - ", - ], Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/docs/api-commands.md", "--- id: commands title: CLI Commands --- - -## Doc ", +## Doc +", ], Array [ "/packages/docusaurus-migrate/src/__tests__/__fixtures__/simple_website/docs/api-doc-markdown.md", @@ -585,8 +558,8 @@ title: CLI Commands id: doc-markdown title: Markdown Features --- - -## Doc", +## Doc +", ], ] `; diff --git a/packages/docusaurus-migrate/src/__tests__/migration.test.ts b/packages/docusaurus-migrate/src/__tests__/migration.test.ts index 0ebae2ce6a..d3b6bd6315 100644 --- a/packages/docusaurus-migrate/src/__tests__/migration.test.ts +++ b/packages/docusaurus-migrate/src/__tests__/migration.test.ts @@ -11,11 +11,11 @@ import fs from 'fs-extra'; import {posixPath} from '@docusaurus/utils'; async function testMigration(siteDir: string, newDir: string) { - const writeMock = jest.spyOn(fs, 'writeFile').mockImplementation(); + const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(); const mkdirpMock = jest.spyOn(fs, 'mkdirp').mockImplementation(); const mkdirsMock = jest.spyOn(fs, 'mkdirs').mockImplementation(); const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); - await migrateDocusaurusProject(siteDir, newDir); + await migrateDocusaurusProject(siteDir, newDir, true, true); expect( writeMock.mock.calls.sort((a, b) => posixPath(a[0] as string).localeCompare(posixPath(b[0] as string)), diff --git a/packages/docusaurus-migrate/src/index.ts b/packages/docusaurus-migrate/src/index.ts index b7480640b3..6d527e44db 100644 --- a/packages/docusaurus-migrate/src/index.ts +++ b/packages/docusaurus-migrate/src/index.ts @@ -171,7 +171,7 @@ export async function migrateDocusaurusProject( } try { - await fs.writeFile( + await fs.outputFile( path.join(newDir, 'docusaurus.config.js'), `module.exports=${JSON.stringify(migrationContext.v2Config, null, 2)}`, ); @@ -388,7 +388,7 @@ async function createPages(context: MigrationContext) { files.map(async (file) => { const filePath = path.join(newDir, 'src', 'pages', file); const content = await fs.readFile(filePath, 'utf-8'); - await fs.writeFile(filePath, migratePage(content)); + await fs.outputFile(filePath, migratePage(content)); }), ); } catch (err) { @@ -408,8 +408,7 @@ async function createDefaultLandingPage({newDir}: MigrationContext) { return ; }; `; - await fs.mkdirp(`${newDir}/src/pages/`); - await fs.writeFile(`${newDir}/src/pages/index.js`, indexPage); + await fs.outputFile(`${newDir}/src/pages/index.js`, indexPage); } async function migrateStaticFiles({siteDir, newDir}: MigrationContext) { @@ -428,7 +427,7 @@ async function migrateBlogFiles(context: MigrationContext) { await Promise.all( files.map(async (file) => { const content = await fs.readFile(file, 'utf-8'); - await fs.writeFile( + await fs.outputFile( file, sanitizedFileContent(content, shouldMigrateMdFiles), ); @@ -508,7 +507,7 @@ async function migrateVersionedDocs( files.map(async (pathToFile) => { if (path.extname(pathToFile) === '.md') { const content = await fs.readFile(pathToFile, 'utf-8'); - await fs.writeFile( + await fs.outputFile( pathToFile, sanitizedFileContent( content.replace(versionRegex, ''), @@ -601,7 +600,7 @@ async function migrateVersionedSidebar( }, {} as SidebarEntries, ); - await fs.writeFile( + await fs.outputFile( path.join( newDir, 'versioned_sidebars', @@ -664,8 +663,10 @@ async function migrateLatestSidebar(context: MigrationContext) { --ifm-color-primary-darkest: ${primaryColor.darken(0.3).hex()}; } `; - await fs.mkdirp(path.join(newDir, 'src', 'css')); - await fs.writeFile(path.join(newDir, 'src', 'css', 'customTheme.css'), css); + await fs.outputFile( + path.join(newDir, 'src', 'css', 'customTheme.css'), + css, + ); context.v2Config.presets[0][1].theme.customCss = path.join( path.relative(newDir, path.join(siteDir, '..')), 'src/css/customTheme.css', @@ -685,7 +686,7 @@ async function migrateLatestDocs(context: MigrationContext) { files.map(async (file) => { if (path.extname(file) === '.md') { const content = await fs.readFile(file, 'utf-8'); - await fs.writeFile( + await fs.outputFile( file, sanitizedFileContent(content, shouldMigrateMdFiles), ); @@ -725,7 +726,7 @@ async function migratePackageFile(context: MigrationContext): Promise { ...packageFile.dependencies, ...deps, }; - await fs.writeFile( + await fs.outputFile( path.join(newDir, 'package.json'), JSON.stringify(packageFile, null, 2), ); @@ -743,7 +744,7 @@ export async function migrateMDToMDX( files.map(async (filePath) => { if (path.extname(filePath) === '.md') { const content = await fs.readFile(filePath, 'utf-8'); - await fs.writeFile(filePath, sanitizedFileContent(content, true)); + await fs.outputFile(filePath, sanitizedFileContent(content, true)); } }), ); diff --git a/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts b/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts index 8dfb206a4d..1b29c49e1b 100644 --- a/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts +++ b/packages/docusaurus-plugin-client-redirects/src/__tests__/writeRedirectFiles.test.ts @@ -194,8 +194,7 @@ describe('writeRedirectFiles', () => { }, ]; - await fs.ensureDir(path.dirname(filesMetadata[0].fileAbsolutePath)); - await fs.writeFile( + await fs.outputFile( filesMetadata[0].fileAbsolutePath, 'file already exists!', ); diff --git a/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts b/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts index c89c67f673..e0a8cabd7a 100644 --- a/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts +++ b/packages/docusaurus-plugin-client-redirects/src/writeRedirectFiles.ts @@ -92,8 +92,7 @@ export async function writeRedirectFile( 'The redirect plugin is not supposed to override existing files.', ); } - await fs.ensureDir(path.dirname(file.fileAbsolutePath)); - await fs.writeFile( + await fs.outputFile( file.fileAbsolutePath, file.fileContent, // Hard security to prevent file overrides diff --git a/packages/docusaurus-plugin-content-blog/src/feed.ts b/packages/docusaurus-plugin-content-blog/src/feed.ts index eb5908977d..58a59b4302 100644 --- a/packages/docusaurus-plugin-content-blog/src/feed.ts +++ b/packages/docusaurus-plugin-content-blog/src/feed.ts @@ -13,7 +13,7 @@ import { mapAsyncSequential, readOutputHTMLFile, } from '@docusaurus/utils'; -import cheerio from 'cheerio'; +import {load as cheerioLoad} from 'cheerio'; import type {DocusaurusConfig} from '@docusaurus/types'; import path from 'path'; import fs from 'fs-extra'; @@ -78,7 +78,7 @@ async function generateBlogFeed({ outDir, siteConfig.trailingSlash, ); - const $ = cheerio.load(content); + const $ = cheerioLoad(content); const feedItem: FeedItem = { title: metadataTitle, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts index 06edd9d6ee..25f438bbe1 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/cli.test.ts @@ -186,8 +186,7 @@ describe('docsVersion', () => { test('first time versioning', async () => { const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); - const ensureMock = jest.spyOn(fs, 'ensureDir').mockImplementation(); - const writeMock = jest.spyOn(fs, 'writeFile'); + const writeMock = jest.spyOn(fs, 'outputFile'); let versionedSidebar; let versionedSidebarPath; writeMock.mockImplementationOnce((filepath, content) => { @@ -238,13 +237,11 @@ describe('docsVersion', () => { copyMock.mockRestore(); writeMock.mockRestore(); consoleMock.mockRestore(); - ensureMock.mockRestore(); }); test('not the first time versioning', async () => { const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); - const ensureMock = jest.spyOn(fs, 'ensureDir').mockImplementation(); - const writeMock = jest.spyOn(fs, 'writeFile'); + const writeMock = jest.spyOn(fs, 'outputFile'); let versionedSidebar; let versionedSidebarPath; writeMock.mockImplementationOnce((filepath, content) => { @@ -295,15 +292,13 @@ describe('docsVersion', () => { copyMock.mockRestore(); writeMock.mockRestore(); consoleMock.mockRestore(); - ensureMock.mockRestore(); }); test('second docs instance versioning', async () => { const pluginId = 'community'; const copyMock = jest.spyOn(fs, 'copy').mockImplementation(); - const ensureMock = jest.spyOn(fs, 'ensureDir').mockImplementation(); - const writeMock = jest.spyOn(fs, 'writeFile'); + const writeMock = jest.spyOn(fs, 'outputFile'); let versionedSidebar; let versionedSidebarPath; writeMock.mockImplementationOnce((filepath, content) => { @@ -350,6 +345,5 @@ describe('docsVersion', () => { copyMock.mockRestore(); writeMock.mockRestore(); consoleMock.mockRestore(); - ensureMock.mockRestore(); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/cli.ts b/packages/docusaurus-plugin-content-docs/src/cli.ts index fea26eae58..ecb5ab0e59 100644 --- a/packages/docusaurus-plugin-content-docs/src/cli.ts +++ b/packages/docusaurus-plugin-content-docs/src/cli.ts @@ -47,8 +47,7 @@ async function createVersionedSidebarFile({ versionedSidebarsDir, `version-${version}-sidebars.json`, ); - await fs.ensureDir(path.dirname(newSidebarFile)); - await fs.writeFile( + await fs.outputFile( newSidebarFile, `${JSON.stringify(sidebars, null, 2)}\n`, 'utf8', @@ -140,8 +139,7 @@ export async function cliDocsVersionCommand( // Update versions.json file. versions.unshift(version); - await fs.ensureDir(path.dirname(versionsJSONFile)); - await fs.writeFile( + await fs.outputFile( versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`, ); diff --git a/packages/docusaurus-theme-translations/update.js b/packages/docusaurus-theme-translations/update.js index 36ab30805c..6576fb182b 100644 --- a/packages/docusaurus-theme-translations/update.js +++ b/packages/docusaurus-theme-translations/update.js @@ -140,7 +140,7 @@ ${warning} async function readMessagesFile(filePath) { if (!(await fs.pathExists(filePath))) { logger.info`File path=${filePath} not found. Creating new translation base file.`; - await fs.writeFile(filePath, '{}\n'); + await fs.outputFile(filePath, '{}\n'); } return JSON.parse((await fs.readFile(filePath)).toString()); } diff --git a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts index 938bb5007d..da0273cc7a 100644 --- a/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/emitUtils.test.ts @@ -120,7 +120,7 @@ describe('readOutputHTMLFile', () => { }); test('generate', async () => { - const writeMock = jest.spyOn(fs, 'writeFile').mockImplementation(() => {}); + const writeMock = jest.spyOn(fs, 'outputFile').mockImplementation(() => {}); const existsMock = jest.spyOn(fs, 'pathExists'); const readMock = jest.spyOn(fs, 'readFile'); diff --git a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts index 53bc48469a..d2b9aea231 100644 --- a/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/jsUtils.test.ts @@ -88,9 +88,9 @@ describe('mapAsyncSequential', () => { test('map sequentially', async () => { const itemToTimeout: Record = { - '1': 50, - '2': 150, - '3': 100, + '1': 200, + '2': 600, + '3': 400, }; const items = Object.keys(itemToTimeout); @@ -112,14 +112,14 @@ describe('mapAsyncSequential', () => { const timeTotal = timeAfter - timeBefore; const totalTimeouts = _.sum(Object.values(itemToTimeout)); - expect(timeTotal).toBeGreaterThanOrEqual(totalTimeouts - 20); + expect(timeTotal).toBeGreaterThanOrEqual(totalTimeouts - 100); expect(itemMapStartsAt['1']).toBeGreaterThanOrEqual(0); expect(itemMapStartsAt['2']).toBeGreaterThanOrEqual( - itemMapEndsAt['1'] - 20, + itemMapEndsAt['1'] - 100, ); expect(itemMapStartsAt['3']).toBeGreaterThanOrEqual( - itemMapEndsAt['2'] - 20, + itemMapEndsAt['2'] - 100, ); }); }); @@ -135,7 +135,7 @@ describe('findAsyncSequential', () => { const items = ['1', '2', '3']; const findFn = jest.fn(async (item: string) => { - await sleep(50); + await sleep(400); return item === '2'; }); @@ -148,8 +148,8 @@ describe('findAsyncSequential', () => { expect(findFn).toHaveBeenNthCalledWith(2, '2'); const timeTotal = timeAfter - timeBefore; - expect(timeTotal).toBeGreaterThanOrEqual(80); - expect(timeTotal).toBeLessThan(120); + expect(timeTotal).toBeGreaterThanOrEqual(600); + expect(timeTotal).toBeLessThan(1000); }); }); diff --git a/packages/docusaurus-utils/src/emitUtils.ts b/packages/docusaurus-utils/src/emitUtils.ts index bb71a99f48..d532985d6c 100644 --- a/packages/docusaurus-utils/src/emitUtils.ts +++ b/packages/docusaurus-utils/src/emitUtils.ts @@ -22,8 +22,7 @@ export async function generate( const filepath = path.join(generatedFilesDir, file); if (skipCache) { - await fs.ensureDir(path.dirname(filepath)); - await fs.writeFile(filepath, content); + await fs.outputFile(filepath, content); return; } @@ -41,8 +40,7 @@ export async function generate( const currentHash = createHash('md5').update(content).digest('hex'); if (lastHash !== currentHash) { - await fs.ensureDir(path.dirname(filepath)); - await fs.writeFile(filepath, content); + await fs.outputFile(filepath, content); fileHash.set(filepath, currentHash); } } diff --git a/packages/docusaurus/src/commands/swizzle/actions.ts b/packages/docusaurus/src/commands/swizzle/actions.ts index 640912d35a..f85bfb7a0f 100644 --- a/packages/docusaurus/src/commands/swizzle/actions.ts +++ b/packages/docusaurus/src/commands/swizzle/actions.ts @@ -144,8 +144,7 @@ export default function ${wrapperComponentName}(props) { } `; - await fs.ensureDir(path.dirname(toPath)); - await fs.writeFile(toPath, content); + await fs.outputFile(toPath, content); return {createdFiles: [toPath]}; } diff --git a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts index a80d88af1f..ae482052e3 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts @@ -552,8 +552,7 @@ describe('extractSiteSourceCodeTranslations', () => { SRC_DIR_NAME, 'site-component-1.jsx', ); - await fs.ensureDir(path.dirname(siteComponentFile1)); - await fs.writeFile( + await fs.outputFile( siteComponentFile1, ` import Translate from '@docusaurus/Translate'; @@ -586,8 +585,7 @@ export default function MySiteComponent1() { const plugin1Dir = await createTmpDir(); const plugin1File1 = path.join(plugin1Dir, 'subpath', 'file1.jsx'); - await fs.ensureDir(path.dirname(plugin1File1)); - await fs.writeFile( + await fs.outputFile( plugin1File1, ` import {translate} from '@docusaurus/Translate'; @@ -606,8 +604,7 @@ export default function MyComponent() { `, ); const plugin1File2 = path.join(plugin1Dir, 'src', 'theme', 'file2.jsx'); - await fs.ensureDir(path.dirname(plugin1File2)); - await fs.writeFile( + await fs.outputFile( plugin1File2, ` import {translate} from '@docusaurus/Translate'; @@ -624,8 +621,7 @@ export default function MyComponent() { // This one should not be found! On purpose! const plugin1File3 = path.join(plugin1Dir, 'unscannedFolder', 'file3.jsx'); - await fs.ensureDir(path.dirname(plugin1File3)); - await fs.writeFile( + await fs.outputFile( plugin1File3, ` import {translate} from '@docusaurus/Translate'; @@ -643,8 +639,7 @@ export default function MyComponent() { const plugin2Dir = await createTmpDir(); const plugin2File = path.join(plugin1Dir, 'subpath', 'file.tsx'); - await fs.ensureDir(path.dirname(plugin2File)); - await fs.writeFile( + await fs.outputFile( plugin2File, ` import Translate, {translate} from '@docusaurus/Translate'; diff --git a/packages/docusaurus/src/server/translations/translations.ts b/packages/docusaurus/src/server/translations/translations.ts index d70b3c926b..1e6fce1367 100644 --- a/packages/docusaurus/src/server/translations/translations.ts +++ b/packages/docusaurus/src/server/translations/translations.ts @@ -131,8 +131,10 @@ Maybe you should remove them? ${unknownKeys}`; } translations will be written at path=${toMessageRelativeFilePath( filePath, )}.`; - await fs.ensureDir(path.dirname(filePath)); - await fs.writeFile(filePath, `${JSON.stringify(mergedContent, null, 2)}\n`); + await fs.outputFile( + filePath, + `${JSON.stringify(mergedContent, null, 2)}\n`, + ); } }