-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(esm): convert
@redwoodjs/cli-helpers
to ESM (#9872)
This PR converts `@redwoodjs/cli-helpers` to a dual ESM/CJS package like #9870 did for `@redwoodjs/project-config`. I didn't do anything differently so see that PR for details. As soon as I converted it, the Jest tests stopped working so @Josh-Walker-GM and I bundled both changes into one PR here. With this PR, we should be able to get all the tests in #9863 passing (about ~15 (out of 1000+) are skipped right now) because Vitest will be able to mock `fs` since it's imported instead of required. That'll be really nice since converting the CLI to ESM will then be possible. I'll confirm that after making this PR. Even if they don't this'll still have been worthwhile. --------- Co-authored-by: Josh GM Walker <56300765+Josh-Walker-GM@users.noreply.github.com>
- Loading branch information
1 parent
d0f036d
commit e94dbf5
Showing
27 changed files
with
294 additions
and
451 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,220 +1,4 @@ | ||
import path from 'path' | ||
import * as memfs from 'memfs' | ||
|
||
const fs = { | ||
...jest.requireActual('fs'), | ||
} | ||
|
||
let mockFiles = {} | ||
|
||
const pathSeparator = path.sep | ||
|
||
const getParentDir = (path) => { | ||
return path.substring(0, path.lastIndexOf(pathSeparator)) | ||
} | ||
|
||
const makeParentDirs = (path) => { | ||
const parentDir = getParentDir(path) | ||
if (parentDir && !(parentDir in mockFiles)) { | ||
mockFiles[parentDir] = undefined | ||
makeParentDirs(parentDir) | ||
} | ||
} | ||
|
||
/** | ||
* This is a custom function that our tests can use during setup to specify | ||
* what the files on the "mock" filesystem should look like when any of the | ||
* `fs` APIs are used. | ||
* | ||
* Sets the state of the mocked file system | ||
* @param newMockFiles - {[filepath]: contents} | ||
*/ | ||
fs.__setMockFiles = (newMockFiles) => { | ||
mockFiles = { ...newMockFiles } | ||
|
||
// Generate all the directories which implicitly exist | ||
Object.keys(mockFiles).forEach((mockPath) => { | ||
if (mockPath.includes(pathSeparator)) { | ||
makeParentDirs(mockPath) | ||
} | ||
}) | ||
} | ||
|
||
fs.__getMockFiles = () => { | ||
return mockFiles | ||
} | ||
|
||
fs.readFileSync = (path) => { | ||
// In prisma v4.3.0, prisma format uses a Wasm module. See https://github.com/prisma/prisma/releases/tag/4.3.0. | ||
// We shouldn't mock this, so we'll use the real fs.readFileSync. | ||
if (path.includes('prisma_fmt_build_bg.wasm')) { | ||
return jest.requireActual('fs').readFileSync(path) | ||
} | ||
|
||
if (path in mockFiles) { | ||
return mockFiles[path] | ||
} else { | ||
const fakeError = new Error( | ||
`Error: ENOENT: no such file or directory, open '${path}'` | ||
) | ||
fakeError.errno = -2 | ||
fakeError.syscall = 'open' | ||
fakeError.code = 'ENOENT' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
} | ||
|
||
fs.writeFileSync = (path, contents) => { | ||
const parentDir = getParentDir(path) | ||
if (parentDir && !fs.existsSync(parentDir)) { | ||
const fakeError = new Error( | ||
`Error: ENOENT: no such file or directory, open '${path}'` | ||
) | ||
fakeError.errno = -2 | ||
fakeError.syscall = 'open' | ||
fakeError.code = 'ENOENT' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
mockFiles[path] = contents | ||
} | ||
|
||
fs.appendFileSync = (path, contents) => { | ||
if (path in mockFiles) { | ||
mockFiles[path] = mockFiles[path] + contents | ||
} else { | ||
fs.writeFileSync(path, contents) | ||
} | ||
} | ||
|
||
fs.rmSync = (path, options = {}) => { | ||
if (fs.existsSync(path)) { | ||
if (options.recursive) { | ||
Object.keys(mockFiles).forEach((mockedPath) => { | ||
if (mockedPath.startsWith(path)) { | ||
delete mockFiles[mockedPath] | ||
} | ||
}) | ||
} else { | ||
if (mockFiles[path] === undefined) { | ||
const children = fs.readdirSync(path) | ||
if (children.length !== 0) { | ||
const fakeError = new Error( | ||
`NodeError [SystemError]: Path is a directory: rm returned EISDIR (is a directory) ${path}` | ||
) | ||
fakeError.errno = 21 | ||
fakeError.syscall = 'rm' | ||
fakeError.code = 'ERR_FS_EISDIR' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
} | ||
delete mockFiles[path] | ||
} | ||
} else { | ||
const fakeError = new Error( | ||
`Error: ENOENT: no such file or directory, stat '${path}'` | ||
) | ||
fakeError.errno = -2 | ||
fakeError.syscall = 'stat' | ||
fakeError.code = 'ENOENT' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
} | ||
|
||
fs.unlinkSync = (path) => { | ||
if (path in mockFiles) { | ||
delete mockFiles[path] | ||
} else { | ||
const fakeError = new Error( | ||
`Error: ENOENT: no such file or directory, stat '${path}'` | ||
) | ||
fakeError.errno = -2 | ||
fakeError.syscall = 'unlink' | ||
fakeError.code = 'ENOENT' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
} | ||
|
||
fs.existsSync = (path) => { | ||
return path in mockFiles | ||
} | ||
|
||
fs.copyFileSync = (src, dist) => { | ||
fs.writeFileSync(dist, fs.readFileSync(src)) | ||
} | ||
|
||
fs.readdirSync = (path) => { | ||
if (!fs.existsSync(path)) { | ||
const fakeError = new Error( | ||
`Error: ENOENT: no such file or directory, scandir '${path}'` | ||
) | ||
fakeError.errno = -2 | ||
fakeError.syscall = 'scandir' | ||
fakeError.code = 'ENOENT' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
|
||
if (mockFiles[path] !== undefined) { | ||
const fakeError = new Error( | ||
`Error: ENOTDIR: not a directory, scandir '${path}'` | ||
) | ||
fakeError.errno = -20 | ||
fakeError.syscall = 'scandir' | ||
fakeError.code = 'ENOTDIR' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
|
||
const content = [] | ||
Object.keys(mockFiles).forEach((mockedPath) => { | ||
const childPath = mockedPath.substring(path.length + 1) | ||
if ( | ||
mockedPath.startsWith(path) && | ||
!childPath.includes(pathSeparator) && | ||
childPath | ||
) { | ||
content.push(childPath) | ||
} | ||
}) | ||
return content | ||
} | ||
|
||
fs.mkdirSync = (path, options = {}) => { | ||
if (options.recursive) { | ||
makeParentDirs(path) | ||
} | ||
// Directories are represented as paths with an "undefined" value | ||
fs.writeFileSync(path, undefined) | ||
} | ||
|
||
fs.rmdirSync = (path, options = {}) => { | ||
if (!fs.existsSync(path)) { | ||
const fakeError = new Error( | ||
`Error: ENOENT: no such file or directory, rmdir '${path}'` | ||
) | ||
fakeError.errno = -2 | ||
fakeError.syscall = 'rmdir' | ||
fakeError.code = 'ENOENT' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
|
||
if (mockFiles[path] !== undefined) { | ||
const fakeError = new Error( | ||
`Error: ENOTDIR: not a directory, rmdir '${path}'` | ||
) | ||
fakeError.errno = -20 | ||
fakeError.syscall = 'rmdir' | ||
fakeError.code = 'ENOTDIR' | ||
fakeError.path = path | ||
throw fakeError | ||
} | ||
|
||
fs.rmSync(path, options) | ||
} | ||
|
||
module.exports = fs | ||
export * from 'memfs' | ||
export default memfs.fs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import * as esbuild from 'esbuild' | ||
|
||
const options = { | ||
entryPoints: ['./src/index.ts'], | ||
outdir: 'dist', | ||
|
||
platform: 'node', | ||
target: ['node20'], | ||
bundle: true, | ||
packages: 'external', | ||
|
||
logLevel: 'info', | ||
metafile: true, | ||
} | ||
|
||
await esbuild.build({ | ||
...options, | ||
format: 'esm', | ||
outExtension: { '.js': '.mjs' }, | ||
}) | ||
|
||
await esbuild.build({ | ||
...options, | ||
format: 'cjs', | ||
outExtension: { '.js': '.cjs' }, | ||
}) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.