UNPKG

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