mirror of https://github.com/status-im/metro.git
Clean-up Module methods/properties
Reviewed By: jeanlauliac Differential Revision: D7894084 fbshipit-source-id: 1a4826d272da51f8beea44ba9b82fa685d254fbe
This commit is contained in:
parent
9a1bfe6388
commit
e47fdf6f59
|
@ -137,22 +137,17 @@ class Bundler {
|
|||
|
||||
this._depGraphPromise = DependencyGraph.load({
|
||||
assetExts: opts.assetExts,
|
||||
assetRegistryPath: opts.assetRegistryPath,
|
||||
blacklistRE: opts.blacklistRE,
|
||||
experimentalCaches: true,
|
||||
extraNodeModules: opts.extraNodeModules,
|
||||
getPolyfills: opts.getPolyfills,
|
||||
hasteImplModulePath: opts.hasteImplModulePath,
|
||||
maxWorkers: opts.maxWorkers,
|
||||
platforms: new Set(opts.platforms),
|
||||
polyfillModuleNames: opts.polyfillModuleNames,
|
||||
projectRoots: opts.projectRoots,
|
||||
providesModuleNodeModules:
|
||||
opts.providesModuleNodeModules || defaults.providesModuleNodeModules,
|
||||
reporter: opts.reporter,
|
||||
resolveRequest: opts.resolveRequest,
|
||||
sourceExts: opts.sourceExts,
|
||||
transformCode: this.transformFile.bind(this),
|
||||
watch: opts.watch,
|
||||
});
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ beforeEach(() => {
|
|||
|
||||
describe('traverseDependencies', function() {
|
||||
let fs;
|
||||
let Module;
|
||||
let traverseDependencies;
|
||||
let transformFile;
|
||||
let transformHelpers;
|
||||
let defaults;
|
||||
let UnableToResolveError;
|
||||
|
@ -97,7 +97,7 @@ describe('traverseDependencies', function() {
|
|||
return await Promise.all(
|
||||
[...dependencies].map(async path => {
|
||||
const dep = dgraph.getModuleForPath(path);
|
||||
const moduleDependencies = (await dep.read()).dependencies;
|
||||
const moduleDependencies = (await transformFile(path)).dependencies;
|
||||
|
||||
return {
|
||||
path: dep.path,
|
||||
|
@ -115,7 +115,6 @@ describe('traverseDependencies', function() {
|
|||
jest.mock('fs', () => new (require('metro-memory-fs'))());
|
||||
|
||||
fs = require('fs');
|
||||
Module = require('../../node-haste/Module');
|
||||
traverseDependencies = require('../traverseDependencies');
|
||||
transformHelpers = require('../../lib/transformHelpers');
|
||||
({
|
||||
|
@ -131,24 +130,23 @@ describe('traverseDependencies', function() {
|
|||
platforms: new Set(['ios', 'android']),
|
||||
maxWorkers: 1,
|
||||
resetCache: true,
|
||||
transformCode: (module, sourceCode, transformOptions) => {
|
||||
return new Promise(resolve => {
|
||||
// require call must stay inline, so the latest defined mock is used!
|
||||
const code = require('fs').readFileSync(module.path, 'utf8');
|
||||
const deps = {dependencies: []};
|
||||
|
||||
if (!module.path.endsWith('.json')) {
|
||||
deps.dependencies = extractDependencies(code);
|
||||
}
|
||||
|
||||
resolve({...deps, code});
|
||||
});
|
||||
},
|
||||
getTransformCacheKey: () => 'abcdef',
|
||||
reporter: require('../../lib/reporting').nullReporter,
|
||||
sourceExts: ['js', 'json'],
|
||||
watch: true,
|
||||
};
|
||||
|
||||
transformFile = async filePath => {
|
||||
// require call must stay inline, so the latest defined mock is used!
|
||||
const code = require('fs').readFileSync(filePath, 'utf8');
|
||||
const deps = {dependencies: []};
|
||||
|
||||
if (!filePath.endsWith('.json')) {
|
||||
deps.dependencies = extractDependencies(code);
|
||||
}
|
||||
|
||||
return {...deps, code};
|
||||
};
|
||||
});
|
||||
|
||||
describe('get sync dependencies (posix)', () => {
|
||||
|
@ -3462,46 +3460,13 @@ describe('traverseDependencies', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Asset module dependencies', () => {
|
||||
let DependencyGraph;
|
||||
let processDgraph;
|
||||
|
||||
beforeEach(() => {
|
||||
DependencyGraph = require('../../node-haste/DependencyGraph');
|
||||
processDgraph = processDgraphFor.bind(null, DependencyGraph);
|
||||
});
|
||||
|
||||
it.skip('allows setting dependencies for asset modules (broken)', async () => {
|
||||
const assetDependencies = ['/root/apple.png', '/root/banana.png'];
|
||||
|
||||
setMockFileSystem({
|
||||
root: {
|
||||
'index.js': 'require("./a.png")',
|
||||
'a.png': '',
|
||||
'apple.png': '',
|
||||
'banana.png': '',
|
||||
},
|
||||
});
|
||||
|
||||
const opts = {...defaults, assetDependencies, projectRoots: ['/root']};
|
||||
await processDgraph(opts, async dgraph => {
|
||||
const {dependencies} = await dgraph.getDependencies({
|
||||
entryPath: '/root/index.js',
|
||||
});
|
||||
const [, assetModule] = dependencies;
|
||||
const deps = await assetModule.getDependencies();
|
||||
expect(deps).toBe(assetDependencies);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Deterministic order of dependencies', () => {
|
||||
let callDeferreds, dependencyGraph, moduleReadDeferreds;
|
||||
let moduleRead;
|
||||
let originalTransformFile;
|
||||
let DependencyGraph;
|
||||
|
||||
beforeEach(() => {
|
||||
moduleRead = Module.prototype.read;
|
||||
originalTransformFile = transformFile;
|
||||
DependencyGraph = require('../../node-haste/DependencyGraph');
|
||||
setMockFileSystem({
|
||||
root: {
|
||||
|
@ -3533,13 +3498,13 @@ describe('traverseDependencies', function() {
|
|||
moduleReadDeferreds = {};
|
||||
callDeferreds = [defer(), defer()]; // [a.js, b.js]
|
||||
|
||||
Module.prototype.read = jest.genMockFn().mockImplementation(function() {
|
||||
const returnValue = moduleRead.apply(this, arguments);
|
||||
if (/\/[ab]\.js$/.test(this.path)) {
|
||||
let deferred = moduleReadDeferreds[this.path];
|
||||
transformFile = jest.genMockFn().mockImplementation((path, ...args) => {
|
||||
const returnValue = originalTransformFile(path, ...args);
|
||||
if (/\/[ab]\.js$/.test(path)) {
|
||||
let deferred = moduleReadDeferreds[path];
|
||||
if (!deferred) {
|
||||
deferred = moduleReadDeferreds[this.path] = defer(returnValue);
|
||||
const index = Number(this.path.endsWith('b.js')); // 0 or 1
|
||||
deferred = moduleReadDeferreds[path] = defer(returnValue);
|
||||
const index = Number(path.endsWith('b.js')); // 0 or 1
|
||||
callDeferreds[index].resolve();
|
||||
}
|
||||
return deferred.promise;
|
||||
|
@ -3551,7 +3516,7 @@ describe('traverseDependencies', function() {
|
|||
|
||||
afterEach(() => {
|
||||
dependencyGraph.then(dgraph => dgraph.end());
|
||||
Module.prototype.read = moduleRead;
|
||||
transformFile = originalTransformFile;
|
||||
});
|
||||
|
||||
it('produces a deterministic tree if the "a" module resolves first', () => {
|
||||
|
|
|
@ -115,7 +115,7 @@ async function getResolveDependencyFn(
|
|||
|
||||
return (from: string, to: string) => {
|
||||
return dependencyGraph.resolveDependency(
|
||||
dependencyGraph.getModuleForPath(from, false),
|
||||
dependencyGraph.getModuleForPath(from),
|
||||
to,
|
||||
platform,
|
||||
).path;
|
||||
|
|
|
@ -19,7 +19,6 @@ const ModuleCache = require('./ModuleCache');
|
|||
const ResolutionRequest = require('./DependencyGraph/ResolutionRequest');
|
||||
|
||||
const fs = require('fs');
|
||||
const parsePlatformFilePath = require('./lib/parsePlatformFilePath');
|
||||
const path = require('path');
|
||||
const toLocalPath = require('../node-haste/lib/toLocalPath');
|
||||
|
||||
|
@ -29,32 +28,24 @@ const {
|
|||
Logger: {createActionStartEntry, createActionEndEntry, log},
|
||||
} = require('metro-core');
|
||||
|
||||
import type {WorkerOptions} from '../JSTransformer/worker';
|
||||
import type {TransformResultDependency} from '../ModuleGraph/types.flow';
|
||||
import type {Reporter} from '../lib/reporting';
|
||||
import type {ModuleMap} from './DependencyGraph/ModuleResolution';
|
||||
import type {TransformCode} from './Module';
|
||||
import type Package from './Package';
|
||||
import type {HasteFS} from './types';
|
||||
import type {CustomResolver} from 'metro-resolver';
|
||||
|
||||
type Options = {|
|
||||
+assetExts: Array<string>,
|
||||
+assetRegistryPath: string,
|
||||
+blacklistRE?: RegExp,
|
||||
+experimentalCaches: boolean,
|
||||
+extraNodeModules: ?{},
|
||||
+getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>,
|
||||
+hasteImplModulePath?: string,
|
||||
+maxWorkers: number,
|
||||
+platforms: Set<string>,
|
||||
+polyfillModuleNames?: Array<string>,
|
||||
+projectRoots: $ReadOnlyArray<string>,
|
||||
+providesModuleNodeModules: Array<string>,
|
||||
+reporter: Reporter,
|
||||
+resolveRequest: ?CustomResolver,
|
||||
+sourceExts: Array<string>,
|
||||
+transformCode: TransformCode,
|
||||
+watch: boolean,
|
||||
|};
|
||||
|
||||
|
@ -195,30 +186,14 @@ class DependencyGraph extends EventEmitter {
|
|||
const {_opts} = this;
|
||||
return new ModuleCache(
|
||||
{
|
||||
assetDependencies: [_opts.assetRegistryPath],
|
||||
getClosestPackage: this._getClosestPackage.bind(this),
|
||||
hasteImplModulePath: _opts.hasteImplModulePath,
|
||||
roots: _opts.projectRoots,
|
||||
transformCode: _opts.transformCode,
|
||||
},
|
||||
_opts.platforms,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise with the direct dependencies the module associated to
|
||||
* the given entryPath has.
|
||||
*/
|
||||
async getShallowDependencies(
|
||||
entryPath: string,
|
||||
transformOptions: WorkerOptions,
|
||||
): Promise<$ReadOnlyArray<TransformResultDependency>> {
|
||||
const module = this._moduleCache.getModule(entryPath);
|
||||
const result = await module.read(transformOptions);
|
||||
|
||||
return result.dependencies;
|
||||
}
|
||||
|
||||
getSha1(filename: string): string {
|
||||
const sha1 = this._hasteFS.getSha1(filename);
|
||||
|
||||
|
@ -237,11 +212,7 @@ class DependencyGraph extends EventEmitter {
|
|||
this._haste.end();
|
||||
}
|
||||
|
||||
getModuleForPath(entryFile: string, isPolyfill: boolean): Module {
|
||||
if (isPolyfill) {
|
||||
return this._moduleCache.getPolyfillModule(entryFile);
|
||||
}
|
||||
|
||||
getModuleForPath(entryFile: string): Module {
|
||||
if (this._helpers.isAssetFile(entryFile)) {
|
||||
return this._moduleCache.getAssetModule(entryFile);
|
||||
}
|
||||
|
@ -269,16 +240,6 @@ class DependencyGraph extends EventEmitter {
|
|||
return this._hasteFS.exists(filePath);
|
||||
};
|
||||
|
||||
_getRequestPlatform(entryPath: string, platform: ?string): ?string {
|
||||
if (platform == null) {
|
||||
platform = parsePlatformFilePath(entryPath, this._opts.platforms)
|
||||
.platform;
|
||||
} else if (!this._opts.platforms.has(platform)) {
|
||||
throw new Error('Unrecognized platform: ' + platform);
|
||||
}
|
||||
return platform;
|
||||
}
|
||||
|
||||
getHasteName(filePath: string): string {
|
||||
const hasteName = this._hasteFS.getModuleName(filePath);
|
||||
|
||||
|
@ -288,10 +249,6 @@ class DependencyGraph extends EventEmitter {
|
|||
|
||||
return toLocalPath(this._opts.projectRoots, filePath);
|
||||
}
|
||||
|
||||
createPolyfill(options: {file: string}) {
|
||||
return this._moduleCache.createPolyfill(options);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DependencyGraph;
|
||||
|
|
|
@ -10,25 +10,15 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const isAbsolutePath = require('absolute-path');
|
||||
|
||||
import type {TransformedCode, WorkerOptions} from '../JSTransformer/worker';
|
||||
import type ModuleCache from './ModuleCache';
|
||||
import type {LocalPath} from './lib/toLocalPath';
|
||||
|
||||
type ReadResult = {
|
||||
...TransformedCode,
|
||||
+source: string,
|
||||
};
|
||||
|
||||
export type TransformCode = Function;
|
||||
|
||||
export type ConstructorArgs = {
|
||||
file: string,
|
||||
localPath: LocalPath,
|
||||
moduleCache: ModuleCache,
|
||||
transformCode: TransformCode,
|
||||
};
|
||||
|
||||
class Module {
|
||||
|
@ -36,10 +26,9 @@ class Module {
|
|||
path: string;
|
||||
|
||||
_moduleCache: ModuleCache;
|
||||
_transformCode: TransformCode;
|
||||
_sourceCode: ?string;
|
||||
|
||||
constructor({file, localPath, moduleCache, transformCode}: ConstructorArgs) {
|
||||
constructor({file, localPath, moduleCache}: ConstructorArgs) {
|
||||
if (!isAbsolutePath(file)) {
|
||||
throw new Error('Expected file to be absolute path but got ' + file);
|
||||
}
|
||||
|
@ -48,41 +37,13 @@ class Module {
|
|||
this.path = file;
|
||||
|
||||
this._moduleCache = moduleCache;
|
||||
this._transformCode = transformCode;
|
||||
}
|
||||
|
||||
getPackage() {
|
||||
return this._moduleCache.getPackageForModule(this);
|
||||
}
|
||||
|
||||
invalidate() {
|
||||
this._sourceCode = null;
|
||||
}
|
||||
|
||||
_readSourceCode(): string {
|
||||
if (this._sourceCode == null) {
|
||||
this._sourceCode = fs.readFileSync(this.path, 'utf8');
|
||||
}
|
||||
|
||||
return this._sourceCode;
|
||||
}
|
||||
|
||||
async read(transformOptions: WorkerOptions): Promise<ReadResult> {
|
||||
const result: TransformedCode = await this._transformCode(
|
||||
this,
|
||||
transformOptions,
|
||||
);
|
||||
|
||||
const module = this;
|
||||
|
||||
return {
|
||||
dependencies: result.dependencies,
|
||||
output: result.output,
|
||||
get source() {
|
||||
return module._readSourceCode();
|
||||
},
|
||||
};
|
||||
}
|
||||
invalidate() {}
|
||||
|
||||
isAsset() {
|
||||
return false;
|
||||
|
|
|
@ -13,48 +13,34 @@
|
|||
const AssetModule = require('./AssetModule');
|
||||
const Module = require('./Module');
|
||||
const Package = require('./Package');
|
||||
const Polyfill = require('./Polyfill');
|
||||
|
||||
const toLocalPath = require('./lib/toLocalPath');
|
||||
|
||||
import type {TransformCode} from './Module';
|
||||
|
||||
type GetClosestPackageFn = (filePath: string) => ?string;
|
||||
|
||||
type Options = {|
|
||||
assetDependencies: Array<string>,
|
||||
hasteImplModulePath?: string,
|
||||
getClosestPackage: GetClosestPackageFn,
|
||||
roots: $ReadOnlyArray<string>,
|
||||
transformCode: TransformCode,
|
||||
|};
|
||||
|
||||
class ModuleCache {
|
||||
_assetDependencies: Array<string>;
|
||||
_getClosestPackage: GetClosestPackageFn;
|
||||
_moduleCache: {[filePath: string]: Module, __proto__: null};
|
||||
_packageCache: {[filePath: string]: Package, __proto__: null};
|
||||
_packageModuleMap: WeakMap<Module, string>;
|
||||
_platforms: Set<string>;
|
||||
_transformCode: TransformCode;
|
||||
_roots: $ReadOnlyArray<string>;
|
||||
_opts: Options;
|
||||
|
||||
constructor(options: Options, platforms: Set<string>) {
|
||||
const {
|
||||
assetDependencies,
|
||||
getClosestPackage,
|
||||
roots,
|
||||
transformCode,
|
||||
} = options;
|
||||
const {getClosestPackage, roots} = options;
|
||||
this._opts = options;
|
||||
this._assetDependencies = assetDependencies;
|
||||
this._getClosestPackage = getClosestPackage;
|
||||
this._moduleCache = Object.create(null);
|
||||
this._packageCache = Object.create(null);
|
||||
this._packageModuleMap = new WeakMap();
|
||||
this._platforms = platforms;
|
||||
this._transformCode = transformCode;
|
||||
this._roots = roots;
|
||||
}
|
||||
|
||||
|
@ -65,7 +51,6 @@ class ModuleCache {
|
|||
localPath: toLocalPath(this._roots, filePath),
|
||||
moduleCache: this,
|
||||
options: this._getModuleOptions(),
|
||||
transformCode: this._transformCode,
|
||||
});
|
||||
}
|
||||
return this._moduleCache[filePath];
|
||||
|
@ -86,20 +71,11 @@ class ModuleCache {
|
|||
localPath: toLocalPath(this._roots, filePath),
|
||||
moduleCache: this,
|
||||
options: this._getModuleOptions(),
|
||||
transformCode: this._transformCode,
|
||||
});
|
||||
}
|
||||
return this._moduleCache[filePath];
|
||||
}
|
||||
|
||||
getPolyfillModule(filePath: string) {
|
||||
if (!this._moduleCache[filePath]) {
|
||||
this._moduleCache[filePath] = this.createPolyfill({file: filePath});
|
||||
}
|
||||
|
||||
return this._moduleCache[filePath];
|
||||
}
|
||||
|
||||
getPackage(filePath: string): Package {
|
||||
if (!this._packageCache[filePath]) {
|
||||
this._packageCache[filePath] = new Package({
|
||||
|
@ -128,17 +104,6 @@ class ModuleCache {
|
|||
return this.getPackage(packagePath);
|
||||
}
|
||||
|
||||
createPolyfill({file}: {file: string}) {
|
||||
/* $FlowFixMe: there are missing arguments. */
|
||||
return new Polyfill({
|
||||
file,
|
||||
localPath: toLocalPath(this._roots, file),
|
||||
moduleCache: this,
|
||||
options: this._getModuleOptions(),
|
||||
transformCode: this._transformCode,
|
||||
});
|
||||
}
|
||||
|
||||
processFileChange(type: string, filePath: string) {
|
||||
if (this._moduleCache[filePath]) {
|
||||
this._moduleCache[filePath].invalidate();
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Module = require('./Module');
|
||||
|
||||
import type {ConstructorArgs} from './Module';
|
||||
|
||||
class Polyfill extends Module {
|
||||
_id: string;
|
||||
_dependencies: Array<string>;
|
||||
|
||||
constructor(
|
||||
options: ConstructorArgs & {
|
||||
id: string,
|
||||
dependencies: Array<string>,
|
||||
},
|
||||
) {
|
||||
super(options);
|
||||
this._id = options.id;
|
||||
this._dependencies = options.dependencies;
|
||||
}
|
||||
|
||||
isHaste() {
|
||||
return false;
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
getPackage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
async getDependencies() {
|
||||
return this._dependencies;
|
||||
}
|
||||
|
||||
isPolyfill() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Polyfill;
|
|
@ -10,43 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
jest.mock('fs', () => new (require('metro-memory-fs'))());
|
||||
|
||||
const AssetModule = require('../AssetModule');
|
||||
const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelpers');
|
||||
const ModuleCache = require('../ModuleCache');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('AssetModule:', () => {
|
||||
const defaults = {file: '/arbitrary.png'};
|
||||
|
||||
beforeEach(() => {
|
||||
fs.reset();
|
||||
fs.mkdirSync('/root');
|
||||
fs.writeFileSync('/root/image.png', 'png data');
|
||||
});
|
||||
|
||||
it('is an asset', () => {
|
||||
expect(new AssetModule(defaults).isAsset()).toBe(true);
|
||||
});
|
||||
|
||||
it('returns an empty source code for an asset', async () => {
|
||||
const module = new AssetModule({
|
||||
depGraphHelpers: new DependencyGraphHelpers({
|
||||
providesModuleNodeModules: [],
|
||||
assetExts: ['png'],
|
||||
}),
|
||||
file: '/root/image.png',
|
||||
getTransformCacheKey: () => 'foo',
|
||||
localPath: 'image.png',
|
||||
moduleCache: new ModuleCache({}),
|
||||
transformCode: () => {
|
||||
return Promise.resolve({output: [{code: 'module.exports = "asset";'}]});
|
||||
},
|
||||
});
|
||||
|
||||
const data = await module.read();
|
||||
|
||||
expect(data.output[0].code).toBe('module.exports = "asset";');
|
||||
expect(new AssetModule({file: '/arbitrary.png'}).isAsset()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,37 +10,23 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
jest.mock('fs').mock('../ModuleCache');
|
||||
|
||||
const fs = require('fs');
|
||||
const ModuleCache = require('../ModuleCache');
|
||||
const Module = require('../Module');
|
||||
const ModuleCache = require('../ModuleCache');
|
||||
|
||||
describe('Module', () => {
|
||||
let transformCode;
|
||||
let moduleCache;
|
||||
let module;
|
||||
|
||||
beforeEach(() => {
|
||||
transformCode = jest.fn().mockReturnValue({
|
||||
dependencies: ['stdlib.h', 'conio.h'],
|
||||
output: [{code: 'int main(void) { return -1; }', map: []}],
|
||||
});
|
||||
|
||||
moduleCache = new ModuleCache();
|
||||
moduleCache = new ModuleCache({});
|
||||
|
||||
module = new Module({
|
||||
file: '/root/to/file.js',
|
||||
localPath: 'file.js',
|
||||
moduleCache,
|
||||
transformCode,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.readFileSync.mockReset();
|
||||
});
|
||||
|
||||
it('Returns the correct values for many properties and methods', () => {
|
||||
expect(module.localPath).toBe('file.js');
|
||||
expect(module.path).toBe('/root/to/file.js');
|
||||
|
@ -48,43 +34,4 @@ describe('Module', () => {
|
|||
expect(module.isAsset()).toBe(false);
|
||||
expect(module.isPolyfill()).toBe(false);
|
||||
});
|
||||
|
||||
it('returns the result from the transform code straight away', async () => {
|
||||
fs.readFileSync.mockReturnValue('original code');
|
||||
|
||||
expect(await module.read({})).toEqual({
|
||||
dependencies: ['stdlib.h', 'conio.h'],
|
||||
output: [
|
||||
{
|
||||
code: 'int main(void) { return -1; }',
|
||||
|
||||
map: [],
|
||||
},
|
||||
],
|
||||
source: 'original code',
|
||||
});
|
||||
});
|
||||
|
||||
it('checks that code is only read once until invalidated', async () => {
|
||||
fs.readFileSync.mockReturnValue('original code');
|
||||
|
||||
// Read once. No access to "source", so no reads.
|
||||
await module.read({});
|
||||
expect(fs.readFileSync).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Read again, accessing "source".
|
||||
expect((await module.read({})).source).toEqual('original code');
|
||||
expect(fs.readFileSync).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Read again, accessing "source" again. Still 1 because code was cached.
|
||||
expect((await module.read({})).source).toEqual('original code');
|
||||
expect(fs.readFileSync).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Invalidate.
|
||||
module.invalidate();
|
||||
|
||||
// Read again, this time it will read it.
|
||||
expect((await module.read({})).source).toEqual('original code');
|
||||
expect(fs.readFileSync).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue