1 |
|
2 | import assert from 'assert';
|
3 | import path from 'path';
|
4 | import ParcelConfig from '../src/ParcelConfig';
|
5 | import {
|
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';
|
18 | import {DEFAULT_OPTIONS} from './utils';
|
19 |
|
20 | describe('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 |
|
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 |
|
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 |
|
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 |
|
189 | validateExtends(2, '.parcelrc');
|
190 | }, /"extends" must be a string or array of strings in .parcelrc/);
|
191 |
|
192 | assert.throws(() => {
|
193 |
|
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 | });
|