UNPKG

13 kBJavaScriptView Raw
1// @flow
2import assert from 'assert';
3import path from 'path';
4import ParcelConfig from '../src/ParcelConfig';
5import {
6 validatePackageName,
7 validatePipeline,
8 validateMap,
9 validateExtends,
10 validateConfigFile,
11 mergePipelines,
12 mergeMaps,
13 mergeConfigs,
14 resolveExtends,
15 readAndProcess,
16 resolveParcelConfig
17} from '../src/loadParcelConfig';
18import {DEFAULT_OPTIONS} from './utils';
19
20describe('loadParcelConfig', () => {
21 describe('validatePackageName', () => {
22 it('should error on an invalid official package', () => {
23 assert.throws(() => {
24 validatePackageName(
25 '@parcel/foo-bar',
26 'transform',
27 'transforms',
28 '.parcelrc'
29 );
30 }, /Official parcel transform packages must be named according to "@parcel\/transform-{name}" but got "@parcel\/foo-bar" in .parcelrc./);
31 });
32
33 it('should succeed on a valid official package', () => {
34 validatePackageName(
35 '@parcel/transform-bar',
36 'transform',
37 'transforms',
38 '.parcelrc'
39 );
40 });
41
42 it('should error on an invalid community package', () => {
43 assert.throws(() => {
44 validatePackageName('foo-bar', 'transform', 'transforms', '.parcelrc');
45 }, /Parcel transform packages must be named according to "parcel-transform-{name}" but got "foo-bar" in .parcelrc./);
46
47 assert.throws(() => {
48 validatePackageName(
49 'parcel-foo-bar',
50 'transform',
51 'transforms',
52 '.parcelrc'
53 );
54 }, /Parcel transform packages must be named according to "parcel-transform-{name}" but got "parcel-foo-bar" in .parcelrc./);
55 });
56
57 it('should succeed on a valid community package', () => {
58 validatePackageName(
59 'parcel-transform-bar',
60 'transform',
61 'transforms',
62 '.parcelrc'
63 );
64 });
65
66 it('should error on an invalid scoped package', () => {
67 assert.throws(() => {
68 validatePackageName(
69 '@test/foo-bar',
70 'transform',
71 'transforms',
72 '.parcelrc'
73 );
74 }, /Scoped parcel transform packages must be named according to "@test\/parcel-transform-{name}" but got "@test\/foo-bar" in .parcelrc./);
75
76 assert.throws(() => {
77 validatePackageName(
78 '@test/parcel-foo-bar',
79 'transform',
80 'transforms',
81 '.parcelrc'
82 );
83 }, /Scoped parcel transform packages must be named according to "@test\/parcel-transform-{name}" but got "@test\/parcel-foo-bar" in .parcelrc./);
84 });
85
86 it('should succeed on a valid scoped package', () => {
87 validatePackageName(
88 '@test/parcel-transform-bar',
89 'transform',
90 'transforms',
91 '.parcelrc'
92 );
93 });
94 });
95
96 describe('validatePipeline', () => {
97 it('should require pipeline to be an array', () => {
98 assert.throws(() => {
99 // $FlowFixMe
100 validatePipeline('123', 'resolver', 'resolvers', '.parcelrc');
101 }, /"resolvers" must be an array in .parcelrc/);
102 });
103
104 it('should require pipeline elements to be strings', () => {
105 assert.throws(() => {
106 validatePipeline(
107 // $FlowFixMe
108 [1, 'foo', 3],
109 'resolver',
110 'resolvers',
111 '.parcelrc'
112 );
113 }, /"resolvers" elements must be strings in .parcelrc/);
114 });
115
116 it('should require package names to be valid', () => {
117 assert.throws(() => {
118 validatePipeline(
119 ['parcel-foo-bar'],
120 'resolver',
121 'resolvers',
122 '.parcelrc'
123 );
124 }, /Parcel resolver packages must be named according to "parcel-resolver-{name}" but got "parcel-foo-bar" in .parcelrc./);
125 });
126
127 it('should succeed with an array of valid package names', () => {
128 validatePipeline(
129 ['parcel-resolver-test'],
130 'resolver',
131 'resolvers',
132 '.parcelrc'
133 );
134 });
135
136 it('should support spread elements', () => {
137 validatePipeline(
138 ['parcel-resolver-test', '...'],
139 'resolver',
140 'resolvers',
141 '.parcelrc'
142 );
143 });
144 });
145
146 describe('validateMap', () => {
147 it('should require glob map to be an object', () => {
148 assert.throws(() => {
149 validateMap(
150 // $FlowFixMe
151 'foo',
152 () => {},
153 'transform',
154 'transforms',
155 '.parcelrc'
156 );
157 }, /"transforms" must be an object in .parcelrc/);
158 });
159
160 it('should trigger the validator function for each key', () => {
161 assert.throws(() => {
162 validateMap(
163 {
164 '*.js': ['foo']
165 },
166 validatePipeline,
167 'transform',
168 'transforms',
169 '.parcelrc'
170 );
171 });
172
173 validateMap(
174 {
175 '*.js': ['parcel-transform-foo']
176 },
177 validatePipeline,
178 'transform',
179 'transforms',
180 '.parcelrc'
181 );
182 });
183 });
184
185 describe('validateExtends', () => {
186 it('should require extends to be a string or array of strings', () => {
187 assert.throws(() => {
188 // $FlowFixMe
189 validateExtends(2, '.parcelrc');
190 }, /"extends" must be a string or array of strings in .parcelrc/);
191
192 assert.throws(() => {
193 // $FlowFixMe
194 validateExtends([2, 4], '.parcelrc');
195 }, /"extends" elements must be strings in .parcelrc/);
196 });
197
198 it('should support relative paths', () => {
199 validateExtends('./foo', '.parcelrc');
200 validateExtends(['./foo', './bar'], '.parcelrc');
201 });
202
203 it('should validate package names', () => {
204 assert.throws(() => {
205 validateExtends('foo', '.parcelrc');
206 });
207
208 assert.throws(() => {
209 validateExtends(['foo', 'bar'], '.parcelrc');
210 });
211
212 validateExtends('parcel-config-foo', '.parcelrc');
213 validateExtends(['parcel-config-foo', 'parcel-config-bar'], '.parcelrc');
214 });
215 });
216
217 describe('validateConfigFile', () => {
218 it('should throw on invalid config', () => {
219 assert.throws(() => {
220 validateConfigFile(
221 {
222 filePath: '.parcelrc',
223 extends: 'parcel-config-foo',
224 transforms: {
225 '*.js': ['parcel-invalid-plugin']
226 }
227 },
228 '.parcelrc'
229 );
230 });
231 });
232
233 it('should succeed on valid config', () => {
234 validateConfigFile(
235 {
236 filePath: '.parcelrc',
237 extends: 'parcel-config-foo',
238 transforms: {
239 '*.js': ['parcel-transformer-foo']
240 }
241 },
242 '.parcelrc'
243 );
244 });
245
246 it('should throw error on empty config file', () => {
247 assert.throws(() => {
248 validateConfigFile({}, '.parcelrc');
249 }, /.parcelrc can't be empty/);
250 });
251 });
252
253 describe('mergePipelines', () => {
254 it('should return an empty array if base and extension are null', () => {
255 assert.deepEqual(mergePipelines(null, null), []);
256 });
257
258 it('should return base if extension is null', () => {
259 assert.deepEqual(mergePipelines(['parcel-transform-foo'], null), [
260 'parcel-transform-foo'
261 ]);
262 });
263
264 it('should return extension if base is null', () => {
265 assert.deepEqual(mergePipelines(null, ['parcel-transform-bar']), [
266 'parcel-transform-bar'
267 ]);
268 });
269
270 it('should return extension if there are no spread elements', () => {
271 assert.deepEqual(
272 mergePipelines(['parcel-transform-foo'], ['parcel-transform-bar']),
273 ['parcel-transform-bar']
274 );
275 });
276
277 it('should return merge base into extension if there are spread elements', () => {
278 assert.deepEqual(
279 mergePipelines(
280 ['parcel-transform-foo'],
281 ['parcel-transform-bar', '...', 'parcel-transform-baz']
282 ),
283 ['parcel-transform-bar', 'parcel-transform-foo', 'parcel-transform-baz']
284 );
285 });
286
287 it('should throw if more than one spread element is in a pipeline', () => {
288 assert.throws(() => {
289 mergePipelines(
290 ['parcel-transform-foo'],
291 ['parcel-transform-bar', '...', 'parcel-transform-baz', '...']
292 );
293 }, /Only one spread element can be included in a config pipeline/);
294 });
295 });
296
297 describe('mergeMaps', () => {
298 it('should return an empty object if base and extension are null', () => {
299 assert.deepEqual(mergeMaps(null, null), {});
300 });
301
302 it('should return base if extension is null', () => {
303 assert.deepEqual(mergeMaps({'*.js': 'foo'}, null), {
304 '*.js': 'foo'
305 });
306 });
307
308 it('should return extension if base is null', () => {
309 assert.deepEqual(mergeMaps(null, {'*.js': 'foo'}), {
310 '*.js': 'foo'
311 });
312 });
313
314 it('should merge the objects', () => {
315 assert.deepEqual(
316 mergeMaps({'*.css': 'css', '*.js': 'base-js'}, {'*.js': 'ext-js'}),
317 {'*.js': 'ext-js', '*.css': 'css'}
318 );
319 });
320
321 it('should ensure that extension properties have a higher precidence than base properties', () => {
322 assert.deepEqual(
323 mergeMaps({'*.{js,jsx}': 'base-js'}, {'*.js': 'ext-js'}),
324 {'*.js': 'ext-js', '*.{js,jsx}': 'base-js'}
325 );
326 assert.deepEqual(
327 Object.keys(mergeMaps({'*.{js,jsx}': 'base-js'}, {'*.js': 'ext-js'})),
328 ['*.js', '*.{js,jsx}']
329 );
330 });
331
332 it('should call a merger function if provided', () => {
333 let merger = (a, b) => [a, b];
334 assert.deepEqual(
335 mergeMaps({'*.js': 'base-js'}, {'*.js': 'ext-js'}, merger),
336 {'*.js': ['base-js', 'ext-js']}
337 );
338 });
339 });
340
341 describe('mergeConfigs', () => {
342 it('should merge configs', () => {
343 let base = new ParcelConfig(
344 {
345 filePath: '.parcelrc',
346 resolvers: ['parcel-resolver-base'],
347 transforms: {
348 '*.js': ['parcel-transform-base'],
349 '*.css': ['parcel-transform-css']
350 },
351 bundler: 'parcel-bundler-base'
352 },
353 DEFAULT_OPTIONS.packageManager
354 );
355
356 let ext = {
357 filePath: '.parcelrc',
358 resolvers: ['parcel-resolver-ext', '...'],
359 transforms: {
360 '*.js': ['parcel-transform-ext', '...']
361 }
362 };
363
364 let merged = new ParcelConfig(
365 {
366 filePath: '.parcelrc',
367 resolvers: ['parcel-resolver-ext', 'parcel-resolver-base'],
368 transforms: {
369 '*.js': ['parcel-transform-ext', 'parcel-transform-base'],
370 '*.css': ['parcel-transform-css']
371 },
372 bundler: 'parcel-bundler-base',
373 runtimes: {},
374 namers: [],
375 optimizers: {},
376 packagers: {},
377 reporters: []
378 },
379 DEFAULT_OPTIONS.packageManager
380 );
381
382 assert.deepEqual(mergeConfigs(base, ext), merged);
383 });
384 });
385
386 describe('resolveExtends', () => {
387 it('should resolve a relative path', async () => {
388 let resolved = await resolveExtends(
389 '../.parcelrc',
390 path.join(__dirname, 'fixtures', 'config', 'subfolder', '.parcelrc'),
391 DEFAULT_OPTIONS
392 );
393 assert.equal(
394 resolved,
395 path.join(__dirname, 'fixtures', 'config', '.parcelrc')
396 );
397 });
398
399 it('should resolve a package name', async () => {
400 let resolved = await resolveExtends(
401 '@parcel/config-default',
402 path.join(__dirname, 'fixtures', 'config', 'subfolder', '.parcelrc'),
403 DEFAULT_OPTIONS
404 );
405 assert.equal(resolved, require.resolve('@parcel/config-default'));
406 });
407 });
408
409 describe('readAndProcess', () => {
410 it('should load and merge configs', async () => {
411 let defaultConfig = require('@parcel/config-default');
412 let {config} = await readAndProcess(
413 path.join(__dirname, 'fixtures', 'config', 'subfolder', '.parcelrc'),
414 DEFAULT_OPTIONS
415 );
416
417 assert.deepEqual(config.transforms['*.js'], [
418 'parcel-transformer-sub',
419 'parcel-transformer-base',
420 '...'
421 ]);
422 assert(Object.keys(config.transforms).length > 1);
423 assert.deepEqual(config.resolvers, defaultConfig.resolvers);
424 assert.deepEqual(config.bundler, defaultConfig.bundler);
425 assert.deepEqual(config.namers, defaultConfig.namers || []);
426 assert.deepEqual(config.packagers, defaultConfig.packagers || {});
427 assert.deepEqual(config.optimizers, defaultConfig.optimizers || {});
428 assert.deepEqual(config.reporters, defaultConfig.reporters || []);
429 });
430 });
431
432 describe('resolve', () => {
433 it('should return null if there is no .parcelrc file found', async () => {
434 let resolved = await resolveParcelConfig(__dirname, DEFAULT_OPTIONS);
435 assert.equal(resolved, null);
436 });
437
438 it('should resolve a config if a .parcelrc file is found', async () => {
439 let resolved = await resolveParcelConfig(
440 path.join(__dirname, 'fixtures', 'config', 'subfolder'),
441 DEFAULT_OPTIONS
442 );
443
444 assert(resolved !== null);
445 });
446 });
447});