1- /* eslint global-require: 0, import/no-dynamic-require: 0 */
1+ /* global aw */
22
33const path = require ( 'path' ) ;
44const fs = require ( 'fs' ) ;
55const { addHook } = require ( 'pirates' ) ;
66const sourceMapSupport = require ( 'source-map-support' ) ;
7- const { transformFile, getTransform } = require ( '@after-work.js/transform' ) ;
7+ const { transformFile, getTransform, deleteTransform } = require ( '@after-work.js/transform' ) ;
88const minimatch = require ( 'minimatch' ) ;
99const mod = require ( 'module' ) ;
10+ const requireFromString = require ( 'require-from-string' ) ;
11+ const utils = require ( '@after-work.js/utils' ) ;
1012
11- const originLoader = mod . _load ; //eslint-disable-line
13+ const originLoader = mod . _load ;
1214let removeCompileHook = ( ) => { } ;
1315let removeLoadHook = ( ) => { } ;
1416
@@ -39,32 +41,39 @@ function compileHook(argv, code, filename, virtualMock = false) {
3941 return transformFile ( filename , newArgv , code ) ;
4042}
4143
42- function compile ( value , filename , options ) {
43- const Module = module . constructor ;
44- const m = new Module ( ) ;
44+ function compile ( value , filename , options , injectReact ) {
4545 let src ;
46- let virtualMock = false ;
4746 if ( fs . existsSync ( value ) ) {
4847 src = fs . readFileSync ( value , 'utf8' ) ;
4948 } else {
50- virtualMock = true ;
51- src = `export default ${ value } ` ;
49+ src = `${ injectReact ? 'import React from "react";\n' : '' } export default ${ value } ` ;
5250 }
53- src = compileHook ( options , src , filename , virtualMock ) ;
54- m . _compile ( src , filename ) ; //eslint-disable-line
55- return m . exports ;
51+ src = compileHook ( options , src , filename , true ) ;
52+ return requireFromString ( src ) ;
5653}
5754
5855function hookedLoader ( options , request , parent , isMain ) {
5956 let filename ;
6057 try {
61- filename = mod . _resolveFilename ( request , parent ) ; // eslint-disable-line
58+ filename = mod . _resolveFilename ( request , parent ) ;
6259 } catch ( err ) {
6360 filename = request ;
6461 }
6562
66- for ( const item of options . mocks || [ ] ) { // eslint-disable-line
67- let [ key , value ] = item ; //eslint-disable-line
63+ // Explicit mocks in modules e.g aw.mock(...)
64+ for ( let [ key , [ value , injectReact ] ] of aw . mocks ) {
65+ if ( minimatch ( filename , key ) ) {
66+ if ( value === undefined && fs . existsSync ( filename ) ) {
67+ const src = fs . readFileSync ( filename , 'utf8' ) ;
68+ value = `${ JSON . stringify ( src ) } ` ;
69+ }
70+ return compile ( value , filename , options , injectReact ) ;
71+ }
72+ }
73+
74+ // Global config mocks
75+ for ( const item of options . mocks || [ ] ) {
76+ let [ key , value ] = item ;
6877 if ( minimatch ( filename , key ) ) {
6978 if ( value === undefined && fs . existsSync ( filename ) ) {
7079 const src = fs . readFileSync ( filename , 'utf8' ) ;
@@ -78,9 +87,9 @@ function hookedLoader(options, request, parent, isMain) {
7887
7988function addLoadHook ( options ) {
8089 const loadHook = hookedLoader . bind ( null , options ) ;
81- mod . _load = loadHook ; //eslint-disable-line
90+ mod . _load = loadHook ;
8291 return ( ) => {
83- mod . _load = originLoader ; //eslint-disable-line
92+ mod . _load = originLoader ;
8493 } ;
8594}
8695
@@ -106,7 +115,48 @@ function installSourceMapSupport() {
106115 sourceMapSupportInstalled = true ;
107116}
108117
109- module . exports = function register ( options = { } ) {
118+ class AW {
119+ constructor ( srcFiles , testFiles ) {
120+ this . srcFiles = srcFiles ;
121+ this . testFiles = testFiles ;
122+ this . mocks = new Map ( ) ;
123+ }
124+
125+ canInjectReact ( ) {
126+ try {
127+ require . resolve ( 'react' ) ;
128+ } catch ( _ ) {
129+ return false ;
130+ }
131+ return true ;
132+ }
133+
134+ mock ( mocks , reqs ) {
135+ const injectReact = this . canInjectReact ( ) ;
136+ mocks . forEach ( ( [ key , value ] ) => this . mocks . set ( key , [ value , injectReact ] ) ) ;
137+ const [ filename ] = utils . getCurrentFilenameStackInfo ( this . testFiles ) ;
138+ const deps = utils . getAllDependencies ( this . srcFiles , filename ) ;
139+ deps . forEach ( ( d ) => {
140+ utils . safeDeleteCache ( d ) ;
141+ } ) ;
142+
143+ const mods = reqs . map ( ( r ) => {
144+ const p = require . resolve ( path . resolve ( path . dirname ( filename ) , r ) ) ;
145+ const m = require ( p ) ;
146+ return m . __esModule && m . default ? m . default : m ;
147+ } ) ;
148+
149+ mocks . forEach ( ( [ key ] ) => this . mocks . delete ( key ) ) ;
150+ deps . forEach ( ( d ) => {
151+ utils . safeDeleteCache ( d ) ;
152+ deleteTransform ( d ) ;
153+ } ) ;
154+ return mods ;
155+ }
156+ }
157+
158+ module . exports = function register ( options = { } , srcFiles , testFiles ) {
159+ global . aw = new AW ( srcFiles , testFiles ) ;
110160 installSourceMapSupport ( ) ;
111161 removeCompileHook ( ) ;
112162 removeLoadHook ( ) ;
0 commit comments