UNPKG

21.7 kBJavaScriptView Raw
1// @flow
2
3import assert from 'assert';
4import path from 'path';
5import tempy from 'tempy';
6import {inputFS as fs} from '@parcel/test-utils';
7import {DEFAULT_OPTIONS} from './utils';
8
9import TargetResolver from '../src/TargetResolver';
10
11const COMMON_TARGETS_FIXTURE_PATH = path.join(
12 __dirname,
13 'fixtures/common-targets',
14);
15
16const COMMON_TARGETS_IGNORE_FIXTURE_PATH = path.join(
17 __dirname,
18 'fixtures/common-targets-ignore',
19);
20
21const CUSTOM_TARGETS_FIXTURE_PATH = path.join(
22 __dirname,
23 'fixtures/custom-targets',
24);
25
26const INVALID_TARGETS_FIXTURE_PATH = path.join(
27 __dirname,
28 'fixtures/invalid-targets',
29);
30
31const INVALID_ENGINES_FIXTURE_PATH = path.join(
32 __dirname,
33 'fixtures/invalid-engines',
34);
35
36const INVALID_DISTPATH_FIXTURE_PATH = path.join(
37 __dirname,
38 'fixtures/invalid-distpath',
39);
40
41const CONTEXT_FIXTURE_PATH = path.join(__dirname, 'fixtures/context');
42
43describe('TargetResolver', () => {
44 let cacheDir;
45 beforeEach(() => {
46 cacheDir = tempy.directory();
47 });
48
49 afterEach(() => {
50 return fs.rimraf(cacheDir);
51 });
52
53 it('resolves exactly specified targets', async () => {
54 let targetResolver = new TargetResolver({
55 ...DEFAULT_OPTIONS,
56 targets: {
57 customA: {
58 context: 'browser',
59 distDir: 'customA',
60 },
61 customB: {
62 distDir: 'customB',
63 engines: {
64 node: '>= 8.0.0',
65 },
66 },
67 },
68 });
69
70 assert.deepEqual(
71 await targetResolver.resolve(COMMON_TARGETS_FIXTURE_PATH),
72 {
73 files: [],
74 targets: [
75 {
76 name: 'customA',
77 publicUrl: undefined,
78 distDir: path.resolve('customA'),
79 env: {
80 context: 'browser',
81 includeNodeModules: true,
82 engines: {
83 browsers: ['> 0.25%'],
84 },
85 outputFormat: 'global',
86 isLibrary: false,
87 },
88 sourceMap: undefined,
89 },
90 {
91 name: 'customB',
92 publicUrl: undefined,
93 distDir: path.resolve('customB'),
94 env: {
95 context: 'node',
96 includeNodeModules: false,
97 engines: {
98 node: '>= 8.0.0',
99 },
100 outputFormat: 'commonjs',
101 isLibrary: false,
102 },
103 sourceMap: undefined,
104 },
105 ],
106 },
107 );
108 });
109
110 it('resolves common targets from package.json', async () => {
111 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
112
113 assert.deepEqual(
114 await targetResolver.resolve(COMMON_TARGETS_FIXTURE_PATH),
115 {
116 files: [
117 {filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json')},
118 ],
119 targets: [
120 {
121 name: 'main',
122 distDir: path.join(__dirname, 'fixtures/common-targets/dist/main'),
123 distEntry: 'index.js',
124 publicUrl: '/',
125 env: {
126 context: 'node',
127 engines: {
128 node: '>= 8.0.0',
129 },
130 includeNodeModules: false,
131 outputFormat: 'commonjs',
132 isLibrary: true,
133 },
134 sourceMap: undefined,
135 loc: {
136 filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'),
137 start: {
138 column: 11,
139 line: 2,
140 },
141 end: {
142 column: 30,
143 line: 2,
144 },
145 },
146 },
147 {
148 name: 'module',
149 distDir: path.join(
150 __dirname,
151 'fixtures/common-targets/dist/module',
152 ),
153 distEntry: 'index.js',
154 publicUrl: '/',
155 env: {
156 context: 'browser',
157 engines: {
158 browsers: ['last 1 version'],
159 },
160 includeNodeModules: false,
161 outputFormat: 'esmodule',
162 isLibrary: true,
163 },
164 sourceMap: {
165 inlineSources: true,
166 },
167 loc: {
168 filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'),
169 start: {
170 column: 13,
171 line: 3,
172 },
173 end: {
174 column: 34,
175 line: 3,
176 },
177 },
178 },
179 {
180 name: 'browser',
181 distDir: path.join(
182 __dirname,
183 'fixtures/common-targets/dist/browser',
184 ),
185 distEntry: 'index.js',
186 publicUrl: '/assets',
187 env: {
188 context: 'browser',
189 engines: {
190 browsers: ['last 1 version'],
191 },
192 includeNodeModules: false,
193 outputFormat: 'commonjs',
194 isLibrary: true,
195 },
196 sourceMap: undefined,
197 loc: {
198 filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'),
199 start: {
200 column: 14,
201 line: 4,
202 },
203 end: {
204 column: 36,
205 line: 4,
206 },
207 },
208 },
209 ],
210 },
211 );
212 });
213
214 it('allows ignoring common targets from package.json', async () => {
215 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
216
217 assert.deepEqual(
218 await targetResolver.resolve(COMMON_TARGETS_IGNORE_FIXTURE_PATH),
219 {
220 files: [
221 {
222 filePath: path.join(
223 COMMON_TARGETS_IGNORE_FIXTURE_PATH,
224 'package.json',
225 ),
226 },
227 ],
228 targets: [
229 {
230 name: 'app',
231 distDir: path.join(COMMON_TARGETS_IGNORE_FIXTURE_PATH, 'dist'),
232 distEntry: 'index.js',
233 publicUrl: '/',
234 env: {
235 context: 'node',
236 engines: {
237 node: '>= 8.0.0',
238 },
239 includeNodeModules: false,
240 outputFormat: 'commonjs',
241 isLibrary: false,
242 },
243 sourceMap: undefined,
244 loc: {
245 filePath: path.join(
246 COMMON_TARGETS_IGNORE_FIXTURE_PATH,
247 'package.json',
248 ),
249 start: {
250 column: 10,
251 line: 3,
252 },
253 end: {
254 column: 24,
255 line: 3,
256 },
257 },
258 },
259 ],
260 },
261 );
262 });
263
264 it('resolves custom targets from package.json', async () => {
265 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
266 assert.deepEqual(
267 await targetResolver.resolve(CUSTOM_TARGETS_FIXTURE_PATH),
268 {
269 files: [
270 {filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json')},
271 ],
272 targets: [
273 {
274 name: 'main',
275 distDir: path.join(__dirname, 'fixtures/custom-targets/dist/main'),
276 distEntry: 'index.js',
277 publicUrl: '/',
278 env: {
279 context: 'node',
280 engines: {
281 node: '>= 8.0.0',
282 },
283 includeNodeModules: false,
284 outputFormat: 'commonjs',
285 isLibrary: true,
286 },
287 sourceMap: undefined,
288 loc: {
289 filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json'),
290 start: {
291 column: 11,
292 line: 2,
293 },
294 end: {
295 column: 30,
296 line: 2,
297 },
298 },
299 },
300 {
301 name: 'browserModern',
302 distDir: path.join(
303 __dirname,
304 'fixtures/custom-targets/dist/browserModern',
305 ),
306 distEntry: 'index.js',
307 publicUrl: '/',
308 env: {
309 context: 'browser',
310 engines: {
311 browsers: ['last 1 version'],
312 },
313 includeNodeModules: true,
314 outputFormat: 'global',
315 isLibrary: false,
316 },
317 sourceMap: undefined,
318 loc: {
319 filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json'),
320 start: {
321 column: 20,
322 line: 3,
323 },
324 end: {
325 column: 48,
326 line: 3,
327 },
328 },
329 },
330 {
331 name: 'browserLegacy',
332 distDir: path.join(
333 __dirname,
334 'fixtures/custom-targets/dist/browserLegacy',
335 ),
336 distEntry: 'index.js',
337 publicUrl: '/',
338 env: {
339 context: 'browser',
340 engines: {
341 browsers: ['ie11'],
342 },
343 includeNodeModules: true,
344 outputFormat: 'global',
345 isLibrary: false,
346 },
347 sourceMap: undefined,
348 loc: {
349 filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json'),
350 start: {
351 column: 20,
352 line: 4,
353 },
354 end: {
355 column: 48,
356 line: 4,
357 },
358 },
359 },
360 ],
361 },
362 );
363 });
364
365 it('resolves main target with context from package.json', async () => {
366 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
367 assert.deepEqual(await targetResolver.resolve(CONTEXT_FIXTURE_PATH), {
368 files: [{filePath: path.join(CONTEXT_FIXTURE_PATH, 'package.json')}],
369 targets: [
370 {
371 name: 'main',
372 distDir: path.join(__dirname, 'fixtures/context/dist/main'),
373 distEntry: 'index.js',
374 publicUrl: '/',
375 env: {
376 context: 'node',
377 engines: {
378 browsers: [
379 'last 1 Chrome version',
380 'last 1 Safari version',
381 'last 1 Firefox version',
382 'last 1 Edge version',
383 ],
384 },
385 includeNodeModules: false,
386 isLibrary: true,
387 outputFormat: 'commonjs',
388 },
389 sourceMap: undefined,
390 loc: {
391 filePath: path.join(CONTEXT_FIXTURE_PATH, 'package.json'),
392 start: {
393 column: 11,
394 line: 2,
395 },
396 end: {
397 column: 30,
398 line: 2,
399 },
400 },
401 },
402 ],
403 });
404 });
405
406 it('resolves main target as an application when non-js file extension is used', async () => {
407 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
408 let fixture = path.join(__dirname, 'fixtures/application-targets');
409 assert.deepEqual(await targetResolver.resolve(fixture), {
410 files: [{filePath: path.join(fixture, 'package.json')}],
411 targets: [
412 {
413 name: 'main',
414 distDir: path.join(fixture, 'dist'),
415 distEntry: 'index.html',
416 publicUrl: '/',
417 env: {
418 context: 'browser',
419 engines: {
420 browsers: [
421 'last 1 Chrome version',
422 'last 1 Safari version',
423 'last 1 Firefox version',
424 'last 1 Edge version',
425 ],
426 },
427 includeNodeModules: true,
428 isLibrary: false,
429 outputFormat: 'global',
430 },
431 sourceMap: undefined,
432 loc: {
433 filePath: path.join(fixture, 'package.json'),
434 start: {
435 column: 11,
436 line: 2,
437 },
438 end: {
439 column: 27,
440 line: 2,
441 },
442 },
443 },
444 ],
445 });
446 });
447
448 it('resolves a subset of package.json targets when given a list of names', async () => {
449 let targetResolver = new TargetResolver({
450 ...DEFAULT_OPTIONS,
451 targets: ['main', 'browser'],
452 });
453
454 assert.deepEqual(
455 await targetResolver.resolve(COMMON_TARGETS_FIXTURE_PATH),
456 {
457 files: [
458 {filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json')},
459 ],
460 targets: [
461 {
462 name: 'main',
463 distDir: path.join(__dirname, 'fixtures/common-targets/dist/main'),
464 distEntry: 'index.js',
465 publicUrl: '/',
466 env: {
467 context: 'node',
468 engines: {
469 node: '>= 8.0.0',
470 },
471 includeNodeModules: false,
472 outputFormat: 'commonjs',
473 isLibrary: true,
474 },
475 sourceMap: undefined,
476 loc: {
477 filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'),
478 start: {
479 column: 11,
480 line: 2,
481 },
482 end: {
483 column: 30,
484 line: 2,
485 },
486 },
487 },
488 {
489 name: 'browser',
490 distDir: path.join(
491 __dirname,
492 'fixtures/common-targets/dist/browser',
493 ),
494 distEntry: 'index.js',
495 publicUrl: '/assets',
496 env: {
497 context: 'browser',
498 engines: {
499 browsers: ['last 1 version'],
500 },
501 includeNodeModules: false,
502 outputFormat: 'commonjs',
503 isLibrary: true,
504 },
505 sourceMap: undefined,
506 loc: {
507 filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'),
508 start: {
509 column: 14,
510 line: 4,
511 },
512 end: {
513 column: 36,
514 line: 4,
515 },
516 },
517 },
518 ],
519 },
520 );
521 });
522
523 it('rejects invalid or unknown fields', async () => {
524 let code =
525 '{\n' +
526 '\t"targets": {\n' +
527 '\t\t"main": {\n' +
528 '\t\t\t"includeNodeModules": [\n' +
529 '\t\t\t\t"react",\n' +
530 '\t\t\t\ttrue\n' +
531 '\t\t\t],\n' +
532 '\t\t\t"context": "nodes",\n' +
533 '\t\t\t"outputFormat": "module",\n' +
534 '\t\t\t"sourceMap": {\n' +
535 '\t\t\t\t"sourceRoot": "asd",\n' +
536 '\t\t\t\t"inline": "false",\n' +
537 '\t\t\t\t"verbose": true\n' +
538 '\t\t\t},\n' +
539 '\t\t\t"engines": {\n' +
540 '\t\t\t\t"node": "12",\n' +
541 '\t\t\t\t"browser": "Chrome 70"\n' +
542 '\t\t\t}\n' +
543 '\t\t}\n' +
544 '\t}\n' +
545 '}';
546 let targetResolver = new TargetResolver({
547 ...DEFAULT_OPTIONS,
548 ...JSON.parse(code),
549 });
550
551 // $FlowFixMe assert.rejects is Node 10+
552 await assert.rejects(
553 () => targetResolver.resolve(COMMON_TARGETS_FIXTURE_PATH),
554 {
555 message: 'Invalid target descriptor for target "main"',
556 diagnostics: [
557 {
558 message: 'Invalid target descriptor for target "main"',
559 origin: '@parcel/core',
560 filePath: undefined,
561 language: 'json',
562 codeFrame: {
563 code,
564 codeHighlights: [
565 {
566 start: {line: 6, column: 5},
567 end: {line: 6, column: 8},
568 message: 'Expected a wildcard or filepath',
569 },
570 {
571 start: {line: 8, column: 15},
572 end: {line: 8, column: 21},
573 message: 'Did you mean "node"?',
574 },
575 {
576 start: {line: 9, column: 20},
577 end: {line: 9, column: 27},
578 message: 'Did you mean "esmodule"?',
579 },
580 {
581 start: {line: 12, column: 15},
582 end: {line: 12, column: 21},
583 message: 'Expected type boolean',
584 },
585 {
586 start: {line: 13, column: 5},
587 end: {line: 13, column: 13},
588 message: 'Possible values: "inlineSources"',
589 },
590 {
591 start: {line: 17, column: 5},
592 end: {line: 17, column: 13},
593 message: 'Did you mean "browsers"?',
594 },
595 ],
596 },
597 },
598 ],
599 },
600 );
601 });
602
603 it('rejects invalid or unknown fields in package.json', async () => {
604 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
605 let code = await fs.readFileSync(
606 path.join(INVALID_TARGETS_FIXTURE_PATH, 'package.json'),
607 'utf8',
608 );
609 // $FlowFixMe assert.rejects is Node 10+
610 await assert.rejects(
611 () => targetResolver.resolve(INVALID_TARGETS_FIXTURE_PATH),
612 {
613 diagnostics: [
614 {
615 message: 'Invalid target descriptor for target "module"',
616 origin: '@parcel/core',
617 filePath: path.join(INVALID_TARGETS_FIXTURE_PATH, 'package.json'),
618 language: 'json',
619 codeFrame: {
620 code,
621 codeHighlights: [
622 {
623 start: {line: 9, column: 29},
624 end: {line: 9, column: 35},
625 message: 'Expected type boolean',
626 },
627 {
628 start: {line: 11, column: 7},
629 end: {line: 11, column: 17},
630 message: 'Did you mean "publicUrl"?',
631 },
632 ],
633 },
634 },
635 ],
636 },
637 );
638 });
639
640 it('rejects invalid engines in package.json', async () => {
641 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
642 let code = await fs.readFileSync(
643 path.join(INVALID_ENGINES_FIXTURE_PATH, 'package.json'),
644 'utf8',
645 );
646 // $FlowFixMe assert.rejects is Node 10+
647 await assert.rejects(
648 () => targetResolver.resolve(INVALID_ENGINES_FIXTURE_PATH),
649 {
650 diagnostics: [
651 {
652 message: 'Invalid engines in package.json',
653 origin: '@parcel/core',
654 filePath: path.join(INVALID_ENGINES_FIXTURE_PATH, 'package.json'),
655 language: 'json',
656 codeFrame: {
657 code,
658 codeHighlights: [
659 {
660 end: {
661 column: 13,
662 line: 8,
663 },
664 message: 'Did you mean "browsers"?',
665 start: {
666 column: 5,
667 line: 8,
668 },
669 },
670 {
671 end: {
672 column: 5,
673 line: 7,
674 },
675 message: 'Expected type string',
676 start: {
677 column: 13,
678 line: 5,
679 },
680 },
681 ],
682 },
683 },
684 ],
685 },
686 );
687 });
688
689 it('rejects target distpath in package.json', async () => {
690 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
691 let code = await fs.readFileSync(
692 path.join(INVALID_DISTPATH_FIXTURE_PATH, 'package.json'),
693 'utf8',
694 );
695 // $FlowFixMe assert.rejects is Node 10+
696 await assert.rejects(
697 () => targetResolver.resolve(INVALID_DISTPATH_FIXTURE_PATH),
698 {
699 diagnostics: [
700 {
701 message: 'Invalid distPath for target "legacy"',
702 origin: '@parcel/core',
703 filePath: path.join(INVALID_DISTPATH_FIXTURE_PATH, 'package.json'),
704 language: 'json',
705 codeFrame: {
706 code,
707 codeHighlights: [
708 {
709 end: {
710 column: 13,
711 line: 2,
712 },
713 message: 'Expected type string',
714 start: {
715 column: 13,
716 line: 2,
717 },
718 },
719 ],
720 },
721 },
722 ],
723 },
724 );
725 });
726
727 it('rejects duplicate target paths', async () => {
728 let fixture = path.join(__dirname, 'fixtures/duplicate-targets');
729 let targetResolver = new TargetResolver(DEFAULT_OPTIONS);
730 let code = await fs.readFileSync(
731 path.join(fixture, 'package.json'),
732 'utf8',
733 );
734 // $FlowFixMe assert.rejects is Node 10+
735 await assert.rejects(() => targetResolver.resolve(fixture), {
736 diagnostics: [
737 {
738 message: `Multiple targets have the same destination path "${path.normalize(
739 'dist/index.js',
740 )}"`,
741 origin: '@parcel/core',
742 filePath: path.join(fixture, 'package.json'),
743 language: 'json',
744 codeFrame: {
745 code,
746 codeHighlights: [
747 {
748 end: {
749 column: 25,
750 line: 2,
751 },
752 message: undefined,
753 start: {
754 column: 11,
755 line: 2,
756 },
757 },
758 {
759 end: {
760 column: 27,
761 line: 3,
762 },
763 message: undefined,
764 start: {
765 column: 13,
766 line: 3,
767 },
768 },
769 ],
770 },
771 hints: [
772 'Try removing the duplicate targets, or changing the destination paths.',
773 ],
774 },
775 ],
776 });
777 });
778});