1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | 'use strict';
|
9 |
|
10 | const chalk = require('chalk');
|
11 | const path = require('path');
|
12 | const os = require('os');
|
13 |
|
14 | class ModuleScopePlugin {
|
15 | constructor(appSrc, allowedFiles = []) {
|
16 | this.appSrcs = Array.isArray(appSrc) ? appSrc : [appSrc];
|
17 | this.allowedFiles = new Set(allowedFiles);
|
18 | }
|
19 |
|
20 | apply(resolver) {
|
21 | const { appSrcs } = this;
|
22 | resolver.hooks.file.tapAsync(
|
23 | 'ModuleScopePlugin',
|
24 | (request, contextResolver, callback) => {
|
25 |
|
26 | if (!request.context.issuer) {
|
27 | return callback();
|
28 | }
|
29 | if (
|
30 |
|
31 | request.descriptionFileRoot.indexOf('/node_modules/') !== -1 ||
|
32 | request.descriptionFileRoot.indexOf('\\node_modules\\') !== -1 ||
|
33 |
|
34 | !request.__innerRequest_request
|
35 | ) {
|
36 | return callback();
|
37 | }
|
38 |
|
39 |
|
40 | if (
|
41 | appSrcs.every(appSrc => {
|
42 | const relative = path.relative(appSrc, request.context.issuer);
|
43 |
|
44 | return relative.startsWith('../') || relative.startsWith('..\\');
|
45 | })
|
46 | ) {
|
47 | return callback();
|
48 | }
|
49 | const requestFullPath = path.resolve(
|
50 | path.dirname(request.context.issuer),
|
51 | request.__innerRequest_request
|
52 | );
|
53 | if (this.allowedFiles.has(requestFullPath)) {
|
54 | return callback();
|
55 | }
|
56 |
|
57 |
|
58 | if (
|
59 | appSrcs.every(appSrc => {
|
60 | const requestRelative = path.relative(appSrc, requestFullPath);
|
61 | return (
|
62 | requestRelative.startsWith('../') ||
|
63 | requestRelative.startsWith('..\\')
|
64 | );
|
65 | })
|
66 | ) {
|
67 | const scopeError = new Error(
|
68 | `You attempted to import ${chalk.cyan(
|
69 | request.__innerRequest_request
|
70 | )} which falls outside of the project ${chalk.cyan(
|
71 | 'src/'
|
72 | )} directory. ` +
|
73 | `Relative imports outside of ${chalk.cyan(
|
74 | 'src/'
|
75 | )} are not supported.` +
|
76 | os.EOL +
|
77 | `You can either move it inside ${chalk.cyan(
|
78 | 'src/'
|
79 | )}, or add a symlink to it from project's ${chalk.cyan(
|
80 | 'node_modules/'
|
81 | )}.`
|
82 | );
|
83 | Object.defineProperty(scopeError, '__module_scope_plugin', {
|
84 | value: true,
|
85 | writable: false,
|
86 | enumerable: false,
|
87 | });
|
88 | callback(scopeError, request);
|
89 | } else {
|
90 | callback();
|
91 | }
|
92 | }
|
93 | );
|
94 | }
|
95 | }
|
96 |
|
97 | module.exports = ModuleScopePlugin;
|