Skip to content

Commit

Permalink
fix(ruleset-bundler): virtualFs plugin incompatible with commonjs plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
P0lip committed Feb 25, 2022
1 parent 91a4b80 commit a48381b
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 32 deletions.
100 changes: 100 additions & 0 deletions packages/ruleset-bundler/src/__tests__/index.jest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { serveAssets } from '@stoplight/spectral-test-utils';
import { fetch } from '@stoplight/spectral-runtime';
import * as fs from 'fs';
import { bundleRuleset } from '../index';
import { IO } from '../types';
import { node } from '../presets/node';
import { browser } from '../presets/browser';
import { commonjs } from '../plugins/commonjs';
import { virtualFs } from '../plugins/virtualFs';
import { runtime } from '../presets/runtime';

jest.mock('fs');

describe('Ruleset Bundler', () => {
let io: IO;

beforeEach(() => {
io = {
fs,
fetch,
};

serveAssets({
'/p/.spectral/my-fn.js': `module.exports = function f() { return [] };`,

'/p/spectral.js': `import myFn from './.spectral/my-fn.js';
export default {
rules: {
rule: {
given: '$',
then: { function: myFn },
}
},
};`,
});
});

it('given runtime target, should support commonjs', async () => {
const code = await bundleRuleset('/p/spectral.js', {
target: 'runtime',
plugins: [...runtime(io), commonjs()],
});

expect(code).toContain(`\tvar myFn = function f() { return [] };
\tvar spectral = {
\t rules: {
\t rule: {
\t given: '$',
\t then: { function: myFn },
\t }
\t },
\t};
\treturn spectral;
})();`);
});

it('given browser target, should support commonjs', async () => {
const code = await bundleRuleset('/p/spectral.js', {
target: 'browser',
plugins: [...browser(io), commonjs()],
});

expect(code).toContain(`var myFn = function f() { return [] };
var spectral = {
rules: {
rule: {
given: '$',
then: { function: myFn },
}
},
};
export { spectral as default };`);
});

it('given node target, should support commonjs', async () => {
const code = await bundleRuleset('/p/spectral.js', {
target: 'node',
plugins: [...node(io), virtualFs(io), commonjs()],
});

expect(code).toContain(`var myFn = function f() { return [] };
var spectral = {
rules: {
rule: {
given: '$',
then: { function: myFn },
}
},
};
export { spectral as default };`);
});
});
77 changes: 45 additions & 32 deletions packages/ruleset-bundler/src/plugins/virtualFs.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,48 @@
import { dirname, parse, join, normalize, isAbsolute, isURL } from '@stoplight/path';
import type { Plugin } from 'rollup';
import type { Plugin, PluginContext } from 'rollup';
import type { IO } from '../types';

export const virtualFs = ({ fs }: IO): Plugin => ({
name: '@stoplight-spectral/virtual-fs',
resolveId(source, importer) {
const { protocol } = parse(source);

if (protocol === 'http' || protocol === 'https') {
return null;
}

if (protocol !== 'file' && !/^[./]/.test(source)) {
return null;
}

if (isAbsolute(source)) {
return normalize(source);
}

if (importer !== void 0) {
return join(dirname(importer), source);
}

return source;
},
load(id) {
if (!isURL(id)) {
return fs.promises.readFile(id, 'utf8');
}

return;
},
});
export const virtualFs = ({ fs }: IO): Plugin => {
const recognized = new WeakMap<PluginContext, string[]>();

return {
name: '@stoplight-spectral/virtual-fs',

resolveId(source, importer): string | null {
const { protocol } = parse(source);

if (protocol === 'http' || protocol === 'https') {
return null;
}

if (protocol !== 'file' && !/^[./]/.test(source)) {
return null;
}

let resolvedSource = source;

if (isAbsolute(source)) {
resolvedSource = normalize(source);
} else if (importer !== void 0) {
resolvedSource = join(dirname(importer), source);
}

let existingEntries = recognized.get(this);
if (existingEntries === void 0) {
existingEntries = [];
recognized.set(this, existingEntries);
}

existingEntries.push(resolvedSource);

return resolvedSource;
},
load(id): Promise<string> | undefined {
if (!isURL(id) && recognized.get(this)?.includes(id) === true) {
return fs.promises.readFile(id, 'utf8');
}

return;
},
};
};

0 comments on commit a48381b

Please sign in to comment.