Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: migrate jest-resolve-dependencies to TypeScript #7922

Merged
merged 7 commits into from Feb 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -46,6 +46,7 @@
- `[@jest/core]` Create new package, which is `jest-cli` minus `yargs` and `prompts` ([#7696](https://github.com/facebook/jest/pull/7696))
- `[@jest/transform]`: Migrate to TypeScript ([#7918](https://github.com/facebook/jest/pull/7918))
- `[docs]` Add missing import to docs ([#7928](https://github.com/facebook/jest/pull/7928))
- `[jest-resolve-dependencies]`: Migrate to TypeScript ([#7922](https://github.com/facebook/jest/pull/7922))

### Performance

Expand Down
11 changes: 11 additions & 0 deletions packages/jest-resolve-dependencies/package.json
Expand Up @@ -8,10 +8,21 @@
},
"license": "MIT",
"main": "build/index.js",
"types": "build/index.d.ts",
"dependencies": {
"@jest/types": "^24.1.0",
"jest-regex-util": "^24.0.0",
"jest-snapshot": "^24.1.0"
},
"devDependencies": {
"jest-haste-map": "^24.0.0",
"jest-resolve": "^24.1.0",
"jest-runtime": "^24.1.0"
},
"peerDependencies": {
"jest-haste-map": "^24.0.0",
"jest-resolve": "^24.1.0"
},
"engines": {
"node": ">= 6"
},
Expand Down
Expand Up @@ -3,41 +3,44 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';

const path = require('path');
const {normalize} = require('jest-config');
const {buildSnapshotResolver} = require('jest-snapshot');
const DependencyResolver = require('../index');
import {tmpdir} from 'os';
import path from 'path';
import {Config} from '@jest/types';
import {buildSnapshotResolver} from 'jest-snapshot';
import {makeProjectConfig} from '../../../../TestUtils';

import DependencyResolver from '../index';

const maxWorkers = 1;
let dependencyResolver;
let dependencyResolver: DependencyResolver;
let Runtime;
let config;
const cases = {
let config: Config.ProjectConfig;
const cases: {[key: string]: jest.Mock} = {
fancyCondition: jest.fn(path => path.length > 10),
testRegex: jest.fn(path => /.test.js$/.test(path)),
};
const filter = path => Object.keys(cases).every(key => cases[key](path));
const filter = (path: Config.Path) =>
Object.keys(cases).every(key => cases[key](path));

beforeEach(() => {
Runtime = require('jest-runtime');
jeysal marked this conversation as resolved.
Show resolved Hide resolved
config = normalize(
{
rootDir: '.',
roots: ['./packages/jest-resolve-dependencies'],
},
{},
).options;
return Runtime.createContext(config, {maxWorkers}).then(hasteMap => {
dependencyResolver = new DependencyResolver(
hasteMap.resolver,
hasteMap.hasteFS,
buildSnapshotResolver(config),
);
config = makeProjectConfig({
cacheDirectory: path.resolve(tmpdir(), 'jest-resolve-dependencies-test'),
moduleDirectories: ['node_modules'],
rootDir: '.',
roots: ['./packages/jest-resolve-dependencies'],
});
return Runtime.createContext(config, {maxWorkers, watchman: false}).then(
(hasteMap: any) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could type as HasteMap, but doesn't matter in a test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's what I meant in #7922 (comment), would prefer to do it in another PR though since I expect it to become rather big

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good!

dependencyResolver = new DependencyResolver(
hasteMap.resolver,
hasteMap.hasteFS,
buildSnapshotResolver(config),
);
},
);
});

test('resolves no dependencies for non-existent path', () => {
Expand Down
Expand Up @@ -3,46 +3,42 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {HasteFS} from 'types/HasteMap';
import type {Path} from 'types/Config';
import type {
Resolver,
ResolveModuleConfig,
ResolvedModule,
} from 'types/Resolve';
import type {SnapshotResolver} from 'types/SnapshotResolver';
import {Config, Resolve, Snapshot} from '@jest/types';
import {FS as HasteFS} from 'jest-haste-map';
import Resolver from 'jest-resolve';
import {isSnapshotPath} from 'jest-snapshot';

/**
* DependencyResolver is used to resolve the direct dependencies of a module or
* to retrieve a list of all transitive inverse dependencies.
*/
class DependencyResolver {
_hasteFS: HasteFS;
_resolver: Resolver;
_snapshotResolver: SnapshotResolver;
private _hasteFS: HasteFS;
private _resolver: Resolver;
private _snapshotResolver: Snapshot.SnapshotResolver;

constructor(
resolver: Resolver,
hasteFS: HasteFS,
snapshotResolver: SnapshotResolver,
snapshotResolver: Snapshot.SnapshotResolver,
) {
this._resolver = resolver;
this._hasteFS = hasteFS;
this._snapshotResolver = snapshotResolver;
}

resolve(file: Path, options?: ResolveModuleConfig): Array<Path> {
resolve(
file: Config.Path,
options?: Resolve.ResolveModuleConfig,
): Array<Config.Path> {
const dependencies = this._hasteFS.getDependencies(file);
if (!dependencies) {
return [];
}

return dependencies.reduce((acc, dependency) => {
return dependencies.reduce<Array<Config.Path>>((acc, dependency) => {
if (this._resolver.isCoreModule(dependency)) {
return acc;
}
Expand All @@ -66,23 +62,27 @@ class DependencyResolver {
}

resolveInverseModuleMap(
paths: Set<Path>,
filter: (file: Path) => boolean,
options?: ResolveModuleConfig,
): Array<ResolvedModule> {
paths: Set<Config.Path>,
filter: (file: Config.Path) => boolean,
options?: Resolve.ResolveModuleConfig,
): Array<Resolve.ResolvedModule> {
if (!paths.size) {
return [];
}

const collectModules = (related, moduleMap, changed) => {
const collectModules = (
related: Set<Config.Path>,
moduleMap: Array<Resolve.ResolvedModule>,
changed: Set<Config.Path>,
) => {
const visitedModules = new Set();
const result: Array<ResolvedModule> = [];
const result: Array<Resolve.ResolvedModule> = [];
while (changed.size) {
changed = new Set(
moduleMap.reduce((acc, module) => {
moduleMap.reduce<Array<Config.Path>>((acc, module) => {
if (
visitedModules.has(module.file) ||
!module.dependencies.some(dep => dep && changed.has(dep))
!module.dependencies.some(dep => changed.has(dep))
jeysal marked this conversation as resolved.
Show resolved Hide resolved
) {
return acc;
}
Expand All @@ -98,11 +98,13 @@ class DependencyResolver {
}, []),
);
}
return result.concat(Array.from(related).map(file => ({file})));
return result.concat(
Array.from(related).map(file => ({dependencies: [], file})),
jeysal marked this conversation as resolved.
Show resolved Hide resolved
);
};

const relatedPaths = new Set<Path>();
const changed = new Set();
const relatedPaths = new Set<Config.Path>();
const changed: Set<Config.Path> = new Set();
for (const path of paths) {
if (this._hasteFS.exists(path)) {
const modulePath = isSnapshotPath(path)
Expand All @@ -114,7 +116,7 @@ class DependencyResolver {
}
}
}
const modules = [];
const modules: Array<Resolve.ResolvedModule> = [];
for (const file of this._hasteFS.getAbsoluteFileIterator()) {
modules.push({
dependencies: this.resolve(file, options),
Expand All @@ -125,14 +127,14 @@ class DependencyResolver {
}

resolveInverse(
paths: Set<Path>,
filter: (file: Path) => boolean,
options?: ResolveModuleConfig,
): Array<Path> {
paths: Set<Config.Path>,
filter: (file: Config.Path) => boolean,
options?: Resolve.ResolveModuleConfig,
): Array<Config.Path> {
return this.resolveInverseModuleMap(paths, filter, options).map(
module => module.file,
);
}
}

module.exports = DependencyResolver;
export = DependencyResolver;
12 changes: 12 additions & 0 deletions packages/jest-resolve-dependencies/tsconfig.json
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "build"
},
"references": [
{"path": "../jest-regex-util"},
{"path": "../jest-snapshot"},
{"path": "../jest-types"}
]
}
11 changes: 3 additions & 8 deletions packages/jest-resolve/src/index.ts
Expand Up @@ -6,7 +6,7 @@
*/

import path from 'path';
import {Config} from '@jest/types';
import {Config, Resolve} from '@jest/types';
import {ModuleMap} from 'jest-haste-map';
import {sync as realpath} from 'realpath-native';
import chalk from 'chalk';
Expand All @@ -15,11 +15,6 @@ import isBuiltinModule from './isBuiltinModule';
import defaultResolver from './defaultResolver';
import {ResolverConfig} from './types';

type ResolveModuleConfig = {
skipNodeResolution?: boolean;
paths?: Config.Path[];
};

type FindNodeModuleConfig = {
basedir: Config.Path;
browser?: boolean;
Expand Down Expand Up @@ -102,7 +97,7 @@ class Resolver {
resolveModuleFromDirIfExists(
dirname: Config.Path,
moduleName: string,
options?: ResolveModuleConfig,
options?: Resolve.ResolveModuleConfig,
): Config.Path | null {
const paths = (options && options.paths) || this._options.modulePaths;
const moduleDirectory = this._options.moduleDirectories;
Expand Down Expand Up @@ -185,7 +180,7 @@ class Resolver {
resolveModule(
from: Config.Path,
moduleName: string,
options?: ResolveModuleConfig,
options?: Resolve.ResolveModuleConfig,
): Config.Path {
const dirname = path.dirname(from);
const module = this.resolveModuleFromDirIfExists(
Expand Down
5 changes: 2 additions & 3 deletions packages/jest-snapshot/src/index.ts
Expand Up @@ -6,15 +6,14 @@
*/

import fs from 'fs';
import {Config, Matchers} from '@jest/types';
import {Config, Matchers, Snapshot} from '@jest/types';
import {FS as HasteFS} from 'jest-haste-map';

import diff from 'jest-diff';
import {EXPECTED_COLOR, matcherHint, RECEIVED_COLOR} from 'jest-matcher-utils';
import {
buildSnapshotResolver,
isSnapshotPath,
SnapshotResolver,
EXTENSION,
} from './snapshot_resolver';
import SnapshotState from './State';
Expand All @@ -31,7 +30,7 @@ const fileExists = (filePath: Config.Path, hasteFS: HasteFS): boolean =>
const cleanup = (
hasteFS: HasteFS,
update: Config.SnapshotUpdateState,
snapshotResolver: SnapshotResolver,
snapshotResolver: Snapshot.SnapshotResolver,
) => {
const pattern = '\\.' + EXTENSION + '$';
const files = hasteFS.matchFiles(pattern);
Expand Down
24 changes: 9 additions & 15 deletions packages/jest-snapshot/src/snapshot_resolver.ts
Expand Up @@ -6,25 +6,19 @@
*/

import path from 'path';
import {Config} from '@jest/types';
import {Config, Snapshot} from '@jest/types';
import chalk from 'chalk';

export type SnapshotResolver = {
testPathForConsistencyCheck: string;
resolveSnapshotPath(testPath: Config.Path, extension?: string): Config.Path;
resolveTestPath(snapshotPath: Config.Path, extension?: string): Config.Path;
};

export const EXTENSION = 'snap';
export const DOT_EXTENSION = '.' + EXTENSION;

export const isSnapshotPath = (path: string): boolean =>
path.endsWith(DOT_EXTENSION);

const cache: Map<Config.Path, SnapshotResolver> = new Map();
const cache: Map<Config.Path, Snapshot.SnapshotResolver> = new Map();
export const buildSnapshotResolver = (
config: Config.ProjectConfig,
): SnapshotResolver => {
): Snapshot.SnapshotResolver => {
const key = config.rootDir;
if (!cache.has(key)) {
cache.set(key, createSnapshotResolver(config.snapshotResolver));
Expand All @@ -34,13 +28,13 @@ export const buildSnapshotResolver = (

function createSnapshotResolver(
snapshotResolverPath?: Config.Path | null,
): SnapshotResolver {
): Snapshot.SnapshotResolver {
return typeof snapshotResolverPath === 'string'
? createCustomSnapshotResolver(snapshotResolverPath)
: createDefaultSnapshotResolver();
}

function createDefaultSnapshotResolver(): SnapshotResolver {
function createDefaultSnapshotResolver(): Snapshot.SnapshotResolver {
return {
resolveSnapshotPath: (testPath: Config.Path) =>
path.join(
Expand All @@ -65,10 +59,10 @@ function createDefaultSnapshotResolver(): SnapshotResolver {

function createCustomSnapshotResolver(
snapshotResolverPath: Config.Path,
): SnapshotResolver {
const custom: SnapshotResolver = require(snapshotResolverPath);
): Snapshot.SnapshotResolver {
const custom: Snapshot.SnapshotResolver = require(snapshotResolverPath);

const keys: [keyof SnapshotResolver, string][] = [
const keys: [keyof Snapshot.SnapshotResolver, string][] = [
['resolveSnapshotPath', 'function'],
['resolveTestPath', 'function'],
['testPathForConsistencyCheck', 'string'],
Expand Down Expand Up @@ -101,7 +95,7 @@ function mustImplement(propName: string, requiredType: string) {
);
}

function verifyConsistentTransformations(custom: SnapshotResolver) {
function verifyConsistentTransformations(custom: Snapshot.SnapshotResolver) {
const resolvedSnapshotPath = custom.resolveSnapshotPath(
custom.testPathForConsistencyCheck,
);
Expand Down