Skip to content

Commit

Permalink
Merge pull request #2 from privatenumber/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber authored Aug 20, 2021
2 parents 3414fe5 + 46fd265 commit 31c35d7
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
run: npm run test --if-present
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,31 @@ const helloWorld = fsRequire('/hello-world')
console.log(helloWorld()) // Hello world!
```

## ⚙️ API

### createFsRequire(fs, options?)
Returns a `require(modulePath)` function that resolves from the file-system passed in.

#### fs
Type: `FileSystem`

Required

The file-system to resolve requires from.

#### options
##### options.fs

Type: `boolean | FileSystem`

Code executed the virtual file-system may `require('fs')` and this may either pose as a security concern or yield inconsistent results as the virtual file won't not accessible through the actual `fs` module.

By default `require('fs')` is shimmed to the file-system passed into `createFsRequire`.

To disable this behavior and resolve to the real `fs` module, set this to `true`.

You can also pass in a different file-system too.


## 👨‍👩‍👧 Related
- [fs-monkey](https://github.com/streamich/fs-monkey) - By the same author of [memfs](https://github.com/streamich/memfs). Patches the global `require` to access a virtual fs.
23 changes: 19 additions & 4 deletions src/fs-require.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,14 @@ const realRequire = require;

let idCounter = 0;

export const createFsRequire = (mfs: FileSystem) => {
type Options = {
fs?: boolean | FileSystem;
};

export const createFsRequire = (
mfs: FileSystem,
options?: Options,
) => {
idCounter += 1;
const fsRequireId = idCounter;
const moduleCache = new Map<string, Module>();
Expand All @@ -81,11 +88,19 @@ export const createFsRequire = (mfs: FileSystem) => {
const require = (modulePath: string) => {
if (!isFilePathPattern.test(modulePath)) {
const [moduleName, moduleSubpath] = getBareSpecifier(modulePath) ?? [];

if (moduleName === 'fs') {
if (moduleSubpath) {
throw new Error(`Cannot find module '${modulePath}'`);
const { fs } = options ?? {};
if (!fs) {
if (moduleSubpath) {
throw new Error(`Cannot find module '${modulePath}'`);
}
return mfs;
}

if (fs !== true) {
return fs;
}
return mfs;
}

return realRequire(modulePath);
Expand Down
73 changes: 55 additions & 18 deletions tests/fs-require.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,29 +117,66 @@ test('native module', () => {
expect(fsRequire('/index')).toBe(path);
});

test('mock fs', () => {
const randomNumber = Math.random().toString();
const vol = Volume.fromJSON({
'/index.js': `
const fs = require('fs');
fs.writeFileSync('/test-write', '${randomNumber}');
`,
describe('mock fs', () => {
test('mock fs', () => {
const randomNumber = Math.random().toString();
const vol = Volume.fromJSON({
'/index.js': `
const fs = require('fs');
fs.writeFileSync('/test-write', '${randomNumber}');
`,
});
const fsRequire = createFsRequire(vol);

fsRequire('/index');
expect(vol.readFileSync('/test-write').toString()).toBe(randomNumber);
});
const fsRequire = createFsRequire(vol);

fsRequire('/index');
expect(vol.readFileSync('/test-write').toString()).toBe(randomNumber);
});
test('mock fs - fs/promises fails', () => {
const vol = Volume.fromJSON({
'/index.js': `
const fs = require('fs/promises');
`,
});
const fsRequire = createFsRequire(vol);

test('mock fs - fs/promises fails', () => {
const vol = Volume.fromJSON({
'/index.js': `
const fs = require('fs/promises');
`,
expect(() => fsRequire('/index')).toThrow('Cannot find module \'fs/promises\'');
});
const fsRequire = createFsRequire(vol);

expect(() => fsRequire('/index')).toThrow('Cannot find module \'fs/promises\'');
test('disabled', () => {
const vol = Volume.fromJSON({
'/index.js': `
const fs = require('fs');
module.exports = fs.readdirSync('${__dirname}');
`,
});

const fsRequire = createFsRequire(vol, {
fs: true,
});

const files = fsRequire('/index');
expect(files.includes('fs-require.spec.ts')).toBe(true);
});

test('custom', () => {
const randomNumber = Math.random().toString();
const customFs = Volume.fromJSON({
'/some-file': randomNumber,
});
const vol = Volume.fromJSON({
'/index.js': `
const fs = require('fs');
module.exports = fs.readFileSync('/some-file').toString();
`,
});

const fsRequire = createFsRequire(vol, {
fs: customFs,
});

expect(fsRequire('/index')).toBe(randomNumber);
});
});

test('Works with real fs', () => {
Expand Down

0 comments on commit 31c35d7

Please sign in to comment.