/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 * modified from https://github.com/facebook/create-react-app/blob/master/packages/react-dev-utils/ModuleScopePlugin.js
 */ import path from 'path' ; import { chalk } from '@modern-js/utils' ; export class ModuleScopePlugin { appSrcs : Array < string | RegExp > ; allowedFiles : Set < string > ; allowedDirs : string [ ] ; allowedPatterns : RegExp [ ] ; relativeAllowedDirs : string [ ] ; constructor ( { appSrc , allowedFiles = [ ] , } ) { this . appSrcs = Array . isArray ( appSrc ) ? appSrc : [ appSrc ] ; this . allowedFiles = new Set ( allowedFiles ) ; this . allowedDirs = this . appSrcs . filter ( src => typeof src === 'string' ) as string [ ] ; this . allowedPatterns = this . appSrcs . filter ( src => Object . prototype . toString . call ( src ) === '[object RegExp]' ) as RegExp [ ] ; this . relativeAllowedDirs = this . allowedDirs . map ( allowedDir => `${ path . relative ( path . dirname ( allowedDir ) , allowedDir ) }/` ) ; } apply ( resolver ) { const { allowedFiles , allowedDirs , allowedPatterns , relativeAllowedDirs } = this ; resolver . hooks . file . tapAsync ( 'ModuleScopePlugin' , ( request , contextResolver , callback ) => { if ( ! request . context . issuer ) { return callback ( ) ; } if ( request . descriptionFileRoot . indexOf ( '/node_modules/' ) !== - 1 || request . descriptionFileRoot . indexOf ( '\\node_modules\\' ) !== - 1 || ! request . __innerRequest_request ) { return callback ( ) ; } if ( allowedDirs . every ( allowedDir => { const relative = path . relative ( allowedDir , request . context . issuer ) ; return relative . startsWith ( '../' ) || relative . startsWith ( '..\\' ) ; } ) ) { return callback ( ) ; } const requestFullPath = path . resolve ( path . dirname ( request . context . issuer ) , request . __innerRequest_request ) ; if ( allowedPatterns . some ( allowedPattern => allowedPattern . test ( requestFullPath ) ) ) { return callback ( ) ; } if ( allowedFiles . has ( requestFullPath ) ) { return callback ( ) ; } if ( allowedDirs . every ( allowedDir => { const requestRelative = path . relative ( allowedDir , requestFullPath ) ; return ( requestRelative . startsWith ( '../' ) || requestRelative . startsWith ( '..\\' ) ) ; } ) ) { let message = `You attempted to import ${ chalk . bold ( request . __innerRequest_request ) } which is not allowed. ` ; if ( allowedDirs . length ) { message += `Allowed dirs: ${ chalk . bold ( relativeAllowedDirs . join ( ',' ) ) }. ` ; } if ( allowedPatterns . length ) { message += `Allowed patterns: ${ chalk . bold ( allowedPatterns . map ( p => p . toString ( ) ) . join ( ',' ) ) }. ` ; } message += `Please check the source.moduleScopes configuration.` ; const scopeError = new Error ( message ) ; Object . defineProperty ( scopeError , '__module_scope_plugin' , { value : true , writable : false , enumerable : false , } ) ; return callback ( scopeError , request ) ; } else { return callback ( ) ; } } ) ; } }