Skip to content

Commit a48381b

Browse files
committed
fix(ruleset-bundler): virtualFs plugin incompatible with commonjs plugin
1 parent 91a4b80 commit a48381b

File tree

2 files changed

+145
-32
lines changed

2 files changed

+145
-32
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { serveAssets } from '@stoplight/spectral-test-utils';
2+
import { fetch } from '@stoplight/spectral-runtime';
3+
import * as fs from 'fs';
4+
import { bundleRuleset } from '../index';
5+
import { IO } from '../types';
6+
import { node } from '../presets/node';
7+
import { browser } from '../presets/browser';
8+
import { commonjs } from '../plugins/commonjs';
9+
import { virtualFs } from '../plugins/virtualFs';
10+
import { runtime } from '../presets/runtime';
11+
12+
jest.mock('fs');
13+
14+
describe('Ruleset Bundler', () => {
15+
let io: IO;
16+
17+
beforeEach(() => {
18+
io = {
19+
fs,
20+
fetch,
21+
};
22+
23+
serveAssets({
24+
'/p/.spectral/my-fn.js': `module.exports = function f() { return [] };`,
25+
26+
'/p/spectral.js': `import myFn from './.spectral/my-fn.js';
27+
28+
export default {
29+
rules: {
30+
rule: {
31+
given: '$',
32+
then: { function: myFn },
33+
}
34+
},
35+
};`,
36+
});
37+
});
38+
39+
it('given runtime target, should support commonjs', async () => {
40+
const code = await bundleRuleset('/p/spectral.js', {
41+
target: 'runtime',
42+
plugins: [...runtime(io), commonjs()],
43+
});
44+
45+
expect(code).toContain(`\tvar myFn = function f() { return [] };
46+
47+
\tvar spectral = {
48+
\t rules: {
49+
\t rule: {
50+
\t given: '$',
51+
\t then: { function: myFn },
52+
\t }
53+
\t },
54+
\t};
55+
56+
\treturn spectral;
57+
58+
})();`);
59+
});
60+
61+
it('given browser target, should support commonjs', async () => {
62+
const code = await bundleRuleset('/p/spectral.js', {
63+
target: 'browser',
64+
plugins: [...browser(io), commonjs()],
65+
});
66+
67+
expect(code).toContain(`var myFn = function f() { return [] };
68+
69+
var spectral = {
70+
rules: {
71+
rule: {
72+
given: '$',
73+
then: { function: myFn },
74+
}
75+
},
76+
};
77+
78+
export { spectral as default };`);
79+
});
80+
81+
it('given node target, should support commonjs', async () => {
82+
const code = await bundleRuleset('/p/spectral.js', {
83+
target: 'node',
84+
plugins: [...node(io), virtualFs(io), commonjs()],
85+
});
86+
87+
expect(code).toContain(`var myFn = function f() { return [] };
88+
89+
var spectral = {
90+
rules: {
91+
rule: {
92+
given: '$',
93+
then: { function: myFn },
94+
}
95+
},
96+
};
97+
98+
export { spectral as default };`);
99+
});
100+
});
Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,48 @@
11
import { dirname, parse, join, normalize, isAbsolute, isURL } from '@stoplight/path';
2-
import type { Plugin } from 'rollup';
2+
import type { Plugin, PluginContext } from 'rollup';
33
import type { IO } from '../types';
44

5-
export const virtualFs = ({ fs }: IO): Plugin => ({
6-
name: '@stoplight-spectral/virtual-fs',
7-
resolveId(source, importer) {
8-
const { protocol } = parse(source);
9-
10-
if (protocol === 'http' || protocol === 'https') {
11-
return null;
12-
}
13-
14-
if (protocol !== 'file' && !/^[./]/.test(source)) {
15-
return null;
16-
}
17-
18-
if (isAbsolute(source)) {
19-
return normalize(source);
20-
}
21-
22-
if (importer !== void 0) {
23-
return join(dirname(importer), source);
24-
}
25-
26-
return source;
27-
},
28-
load(id) {
29-
if (!isURL(id)) {
30-
return fs.promises.readFile(id, 'utf8');
31-
}
32-
33-
return;
34-
},
35-
});
5+
export const virtualFs = ({ fs }: IO): Plugin => {
6+
const recognized = new WeakMap<PluginContext, string[]>();
7+
8+
return {
9+
name: '@stoplight-spectral/virtual-fs',
10+
11+
resolveId(source, importer): string | null {
12+
const { protocol } = parse(source);
13+
14+
if (protocol === 'http' || protocol === 'https') {
15+
return null;
16+
}
17+
18+
if (protocol !== 'file' && !/^[./]/.test(source)) {
19+
return null;
20+
}
21+
22+
let resolvedSource = source;
23+
24+
if (isAbsolute(source)) {
25+
resolvedSource = normalize(source);
26+
} else if (importer !== void 0) {
27+
resolvedSource = join(dirname(importer), source);
28+
}
29+
30+
let existingEntries = recognized.get(this);
31+
if (existingEntries === void 0) {
32+
existingEntries = [];
33+
recognized.set(this, existingEntries);
34+
}
35+
36+
existingEntries.push(resolvedSource);
37+
38+
return resolvedSource;
39+
},
40+
load(id): Promise<string> | undefined {
41+
if (!isURL(id) && recognized.get(this)?.includes(id) === true) {
42+
return fs.promises.readFile(id, 'utf8');
43+
}
44+
45+
return;
46+
},
47+
};
48+
};

0 commit comments

Comments
 (0)