Port kbn-pm to TypeScript. (#16732)

This commit is contained in:
Aleh Zasypkin 2018-02-21 10:09:30 +01:00 committed by GitHub
parent d8b3ca27ab
commit cb21a7edec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 9275 additions and 2565 deletions

View file

@ -301,6 +301,8 @@
"supertest": "3.0.0",
"supertest-as-promised": "2.0.2",
"tree-kill": "1.1.0",
"ts-jest": "^22.0.4",
"typescript": "^2.7.2",
"webpack-dev-server": "2.9.1",
"xml2js": "0.4.19",
"xmlbuilder": "9.0.4",

File diff suppressed because one or more lines are too long

View file

@ -5,36 +5,63 @@
"license": "Apache-2.0",
"private": true,
"scripts": {
"build": "webpack"
"build": "webpack",
"prettier": "prettier --write './src/**/*.ts'"
},
"devDependencies": {
"@types/bluebird": "^3.5.20",
"@types/cmd-shim": "^2.0.0",
"@types/cpy": "^5.1.0",
"@types/dedent": "^0.7.0",
"@types/del": "^3.0.0",
"@types/execa": "^0.8.1",
"@types/getopts": "^2.0.0",
"@types/glob": "^5.0.35",
"@types/globby": "^6.1.0",
"@types/has-ansi": "^3.0.0",
"@types/indent-string": "^3.0.0",
"@types/jest": "^22.1.3",
"@types/lodash.clonedeepwith": "^4.5.3",
"@types/log-symbols": "^2.0.0",
"@types/mkdirp": "^0.5.2",
"@types/node": "^6.0.100",
"@types/ora": "^1.3.1",
"@types/read-pkg": "^3.0.0",
"@types/strip-ansi": "^3.0.0",
"@types/strong-log-transformer": "^1.0.0",
"@types/tempy": "^0.1.0",
"@types/wrap-ansi": "^2.0.14",
"@types/write-pkg": "^3.1.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-3": "^6.24.1",
"chalk": "^2.3.0",
"bluebird": "^3.5.1",
"chalk": "^2.3.1",
"cmd-shim": "^2.0.2",
"cpy": "^6.0.0",
"dedent": "^0.7.0",
"del": "^3.0.0",
"execa": "^0.8.0",
"execa": "^0.9.0",
"getopts": "^2.0.0",
"glob": "^7.1.2",
"globby": "^7.1.1",
"globby": "^8.0.1",
"has-ansi": "^3.0.0",
"indent-string": "^3.2.0",
"lodash.clonedeepwith": "^4.5.0",
"log-symbols": "^2.1.0",
"log-symbols": "^2.2.0",
"mkdirp": "^0.5.1",
"ora": "^1.3.0",
"pify": "^3.0.0",
"ora": "^1.4.0",
"prettier": "^1.10.2",
"read-pkg": "^3.0.0",
"spawn-sync": "^1.0.15",
"string-replace-loader": "^1.3.0",
"strip-ansi": "^4.0.0",
"strong-log-transformer": "^1.0.6",
"tempy": "^0.2.1",
"webpack": "^3.10.0",
"ts-loader": "^3.5.0",
"typescript": "^2.7.2",
"webpack": "^3.11.0",
"wrap-ansi": "^3.0.1",
"write-pkg": "^3.1.0"
}

View file

@ -3,14 +3,12 @@ import dedent from 'dedent';
import chalk from 'chalk';
import { resolve } from 'path';
import * as commands from './commands';
import { commands } from './commands';
import { runCommand } from './run';
const getCommand = name => commands[name]; // eslint-disable-line import/namespace
function help() {
const availableCommands = Object.keys(commands)
.map(commandName => getCommand(commandName))
.map(commandName => commands[commandName])
.map(command => `${command.name} - ${command.description}`);
console.log(dedent`
@ -30,7 +28,7 @@ function help() {
`);
}
export async function run(argv) {
export async function run(argv: string[]) {
// We can simplify this setup (and remove this extra handling) once Yarn
// starts forwarding the `--` directly to this script, see
// https://github.com/yarnpkg/yarn/blob/b2d3e1a8fe45ef376b716d597cc79b38702a9320/src/cli/index.js#L174-L182
@ -65,7 +63,7 @@ export async function run(argv) {
const commandOptions = { options, extraArgs, rootPath };
const command = getCommand(commandName);
const command = commands[commandName];
if (command === undefined) {
console.log(
chalk.red(`[${commandName}] is not a valid command, see 'kbn --help'`)

View file

@ -1,10 +1,5 @@
jest.mock('../utils/scripts', () => ({
installInDir: jest.fn(),
runScriptInPackageStreaming: jest.fn(),
}));
jest.mock('../utils/link_project_executables', () => ({
linkProjectExecutables: jest.fn(),
}));
jest.mock('../utils/scripts');
jest.mock('../utils/link_project_executables');
import { resolve } from 'path';
@ -13,17 +8,22 @@ import {
stripAnsiSnapshotSerializer,
} from '../test_helpers';
import { run } from './bootstrap';
import { PackageJson } from '../utils/package_json';
import { Project } from '../utils/project';
import { buildProjectGraph } from '../utils/projects';
import { installInDir, runScriptInPackageStreaming } from '../utils/scripts';
import { linkProjectExecutables } from '../utils/link_project_executables';
const createProject = (fields, path = '.') =>
const mockInstallInDir = installInDir as jest.Mock;
const mockRunScriptInPackageStreaming = runScriptInPackageStreaming as jest.Mock;
const mockLinkProjectExecutables = linkProjectExecutables as jest.Mock;
const createProject = (packageJson: PackageJson, path = '.') =>
new Project(
{
name: 'kibana',
version: '1.0.0',
...fields,
...packageJson,
},
resolve(__dirname, path)
);
@ -78,12 +78,14 @@ test('handles dependencies of dependencies', async () => {
const logMock = jest.spyOn(console, 'log').mockImplementation(noop);
await run(projects, projectGraph, {
extraArgs: [],
options: {},
rootPath: '',
});
logMock.mockRestore();
expect(installInDir.mock.calls).toMatchSnapshot('install in dir');
expect(mockInstallInDir.mock.calls).toMatchSnapshot('install in dir');
expect(logMock.mock.calls).toMatchSnapshot('logs');
});
@ -107,12 +109,14 @@ test('does not run installer if no deps in package', async () => {
const logMock = jest.spyOn(console, 'log').mockImplementation(noop);
await run(projects, projectGraph, {
extraArgs: [],
options: {},
rootPath: '',
});
logMock.mockRestore();
expect(installInDir.mock.calls).toMatchSnapshot('install in dir');
expect(mockInstallInDir.mock.calls).toMatchSnapshot('install in dir');
expect(logMock.mock.calls).toMatchSnapshot('logs');
});
@ -129,14 +133,16 @@ test('handles "frozen-lockfile"', async () => {
const logMock = jest.spyOn(console, 'log').mockImplementation(noop);
await run(projects, projectGraph, {
extraArgs: [],
options: {
'frozen-lockfile': true,
},
rootPath: '',
});
logMock.mockRestore();
expect(installInDir.mock.calls).toMatchSnapshot('install in dir');
expect(mockInstallInDir.mock.calls).toMatchSnapshot('install in dir');
});
test('calls "kbn:bootstrap" scripts and links executables after installing deps', async () => {
@ -161,11 +167,13 @@ test('calls "kbn:bootstrap" scripts and links executables after installing deps'
const logMock = jest.spyOn(console, 'log').mockImplementation(noop);
await run(projects, projectGraph, {
extraArgs: [],
options: {},
rootPath: '',
});
logMock.mockRestore();
expect(linkProjectExecutables.mock.calls).toMatchSnapshot('link bins');
expect(runScriptInPackageStreaming.mock.calls).toMatchSnapshot('script');
expect(mockLinkProjectExecutables.mock.calls).toMatchSnapshot('link bins');
expect(mockRunScriptInPackageStreaming.mock.calls).toMatchSnapshot('script');
});

View file

@ -1,13 +1,22 @@
import chalk from 'chalk';
import { topologicallyBatchProjects } from '../utils/projects';
import {
ProjectGraph,
ProjectMap,
topologicallyBatchProjects,
} from '../utils/projects';
import { linkProjectExecutables } from '../utils/link_project_executables';
import { parallelizeBatches } from '../utils/parallelize';
import { CommandConfig } from './';
export const name = 'bootstrap';
export const description = 'Install dependencies and crosslink projects';
export async function run(projects, projectGraph, { options }) {
export async function run(
projects: ProjectMap,
projectGraph: ProjectGraph,
{ options }: CommandConfig
) {
const batchedProjects = topologicallyBatchProjects(projects, projectGraph);
const frozenLockfile = options['frozen-lockfile'] === true;
@ -39,9 +48,9 @@ export async function run(projects, projectGraph, { options }) {
'\nLinking executables completed, running `kbn:bootstrap` scripts\n'
)
);
await parallelizeBatches(batchedProjects, pkg => {
await parallelizeBatches(batchedProjects, async pkg => {
if (pkg.hasScript('kbn:bootstrap')) {
return pkg.runScriptStreaming('kbn:bootstrap');
await pkg.runScriptStreaming('kbn:bootstrap');
}
});

View file

@ -4,12 +4,18 @@ import { relative } from 'path';
import ora from 'ora';
import { isDirectory } from '../utils/fs';
import { ProjectGraph, ProjectMap } from '../utils/projects';
import { CommandConfig } from './';
export const name = 'clean';
export const description =
'Remove the node_modules and target directories from all projects.';
export async function run(projects, projectGraph, { rootPath }) {
export async function run(
projects: ProjectMap,
projectGraph: ProjectGraph,
{ rootPath }: CommandConfig
) {
const directoriesToDelete = [];
for (const project of projects.values()) {
if (await isDirectory(project.nodeModulesLocation)) {
@ -28,7 +34,8 @@ export async function run(projects, projectGraph, { rootPath }) {
for (const dir of directoriesToDelete) {
const deleting = del(dir, { force: true });
ora.promise(deleting, relative(rootPath, dir));
// Remove once https://github.com/DefinitelyTyped/DefinitelyTyped/pull/23699 is merged.
(ora as any).promise(deleting, relative(rootPath, dir));
await deleting;
}
}

View file

@ -1,7 +0,0 @@
import * as bootstrap from './bootstrap';
import * as clean from './clean';
import * as run from './run';
export { bootstrap };
export { clean };
export { run };

View file

@ -0,0 +1,28 @@
import { ProjectGraph, ProjectMap } from '../utils/projects';
export interface CommandConfig {
extraArgs: string[];
options: { [key: string]: any };
rootPath: string;
}
export interface Command {
name: string;
description: string;
run: (
projects: ProjectMap,
projectGraph: ProjectGraph,
config: CommandConfig
) => Promise<void>;
}
import * as bootstrap from './bootstrap';
import * as clean from './clean';
import * as run from './run';
export const commands: { [key: string]: Command } = {
bootstrap,
clean,
run,
};

View file

@ -1,13 +1,22 @@
import chalk from 'chalk';
import { topologicallyBatchProjects } from '../utils/projects';
import {
ProjectGraph,
ProjectMap,
topologicallyBatchProjects,
} from '../utils/projects';
import { parallelizeBatches } from '../utils/parallelize';
import { CommandConfig } from './';
export const name = 'run';
export const description =
'Run script defined in package.json in each package that contains that script.';
export async function run(projects, projectGraph, { extraArgs }) {
export async function run(
projects: ProjectMap,
projectGraph: ProjectGraph,
{ extraArgs }: CommandConfig
) {
const batchedProjects = topologicallyBatchProjects(projects, projectGraph);
if (extraArgs.length === 0) {
@ -26,9 +35,9 @@ export async function run(projects, projectGraph, { extraArgs }) {
)
);
await parallelizeBatches(batchedProjects, pkg => {
await parallelizeBatches(batchedProjects, async pkg => {
if (pkg.hasScript(scriptName)) {
return pkg.runScriptStreaming(scriptName, scriptArgs);
await pkg.runScriptStreaming(scriptName, scriptArgs);
}
});
}

View file

@ -1,9 +1,14 @@
import { resolve } from 'path';
export type ProjectPathOptions = {
'skip-kibana-extra'?: boolean;
'skip-kibana'?: boolean;
};
/**
* Returns all the paths where plugins are located
*/
export function getProjectPaths(rootPath, options) {
export function getProjectPaths(rootPath: string, options: ProjectPathOptions) {
const skipKibanaExtra = Boolean(options['skip-kibana-extra']);
const skipKibana = Boolean(options['skip-kibana']);

View file

@ -13,8 +13,15 @@ import {
writePackageJson,
} from '../utils/package_json';
import { isDirectory } from '../utils/fs';
import { Project } from '../utils/project';
export async function buildProductionProjects({ kibanaRoot, buildRoot }) {
export async function buildProductionProjects({
kibanaRoot,
buildRoot,
}: {
kibanaRoot: string;
buildRoot: string;
}) {
const projectPaths = getProjectPaths(kibanaRoot, {
'skip-kibana': true,
'skip-kibana-extra': true,
@ -39,7 +46,10 @@ export async function buildProductionProjects({ kibanaRoot, buildRoot }) {
/**
* Returns only the projects that should be built into the production bundle
*/
async function getProductionProjects(kibanaRoot, projectPaths) {
async function getProductionProjects(
kibanaRoot: string,
projectPaths: string[]
) {
const projects = await getProjects(kibanaRoot, projectPaths);
const buildProjects = new Map();
@ -52,7 +62,7 @@ async function getProductionProjects(kibanaRoot, projectPaths) {
return buildProjects;
}
async function deleteTarget(project) {
async function deleteTarget(project: Project) {
const targetDir = project.targetLocation;
if (await isDirectory(targetDir)) {
@ -60,13 +70,17 @@ async function deleteTarget(project) {
}
}
async function buildProject(project) {
async function buildProject(project: Project) {
if (project.hasScript('build')) {
await project.runScript('build');
}
}
async function copyToBuild(project, kibanaRoot, buildRoot) {
async function copyToBuild(
project: Project,
kibanaRoot: string,
buildRoot: string
) {
// We want the package to have the same relative location within the build
const relativeProjectPath = relative(kibanaRoot, project.path);
const buildProjectPath = resolve(buildRoot, relativeProjectPath);

View file

@ -5,12 +5,13 @@ import { isLinkDependency } from '../utils/package_json';
* All external projects are located within `../kibana-extra/{plugin}` relative
* to Kibana itself.
*/
const isKibanaDep = depVersion => depVersion.includes('../../kibana/');
const isKibanaDep = (depVersion: string) =>
depVersion.includes('../../kibana/');
/**
* This prepares the dependencies for an _external_ project.
*/
export async function prepareExternalProjectDependencies(projectPath) {
export async function prepareExternalProjectDependencies(projectPath: string) {
const project = await Project.fromPath(projectPath);
if (!project.hasDependencies()) {

View file

@ -4,9 +4,10 @@ import indentString from 'indent-string';
import { CliError } from './utils/errors';
import { getProjects, buildProjectGraph } from './utils/projects';
import { getProjectPaths } from './config';
import { getProjectPaths, ProjectPathOptions } from './config';
import { Command, CommandConfig } from './commands';
export async function runCommand(command, config) {
export async function runCommand(command: Command, config: CommandConfig) {
try {
console.log(
chalk.bold(
@ -16,13 +17,16 @@ export async function runCommand(command, config) {
)
);
const projectPaths = getProjectPaths(config.rootPath, config.options);
const projectPaths = getProjectPaths(
config.rootPath,
config.options as ProjectPathOptions
);
const projects = await getProjects(config.rootPath, projectPaths);
const projectGraph = buildProjectGraph(projects);
console.log(
chalk.bold(`Found [${chalk.green(projects.size)}] projects:\n`)
chalk.bold(`Found [${chalk.green(projects.size.toString())}] projects:\n`)
);
for (const pkg of projects.values()) {
console.log(`- ${pkg.name} (${pkg.path})`);

View file

@ -3,9 +3,9 @@ import cloneDeepWith from 'lodash.clonedeepwith';
const repoRoot = resolve(__dirname, '../../../../');
const normalizePaths = value => {
const normalizePaths = (value: any) => {
let didReplacement = false;
const clone = cloneDeepWith(value, v => {
const clone = cloneDeepWith(value, (v: any) => {
if (typeof v === 'string' && v.startsWith(repoRoot)) {
didReplacement = true;
return v
@ -22,11 +22,11 @@ const normalizePaths = value => {
};
export const absolutePathSnapshotSerializer = {
print: (value, serialize) => {
print(value: any, serialize: (val: any) => string) {
return serialize(normalizePaths(value).clone);
},
test: value => {
test(value: any) {
return normalizePaths(value).didReplacement;
},
};

View file

@ -2,11 +2,11 @@ import hasAnsi from 'has-ansi';
import stripAnsi from 'strip-ansi';
export const stripAnsiSnapshotSerializer = {
print: (value, serialize) => {
print(value: string, serialize: (val: string) => string) {
return serialize(stripAnsi(value));
},
test: value => {
test(value: any) {
return typeof value === 'string' && hasAnsi(value);
},
};

View file

@ -4,16 +4,22 @@ import logTransformer from 'strong-log-transformer';
import logSymbols from 'log-symbols';
function generateColors() {
const colorWheel = ['cyan', 'magenta', 'blue', 'yellow', 'green', 'red'].map(
name => chalk[name]
);
const colorWheel = [
chalk.cyan,
chalk.magenta,
chalk.blue,
chalk.yellow,
chalk.green,
chalk.red,
];
const count = colorWheel.length;
let children = 0;
return () => colorWheel[children++ % count];
}
export function spawn(command, args, opts) {
export function spawn(command: string, args: string[], opts: execa.Options) {
return execa(command, args, {
...opts,
stdio: 'inherit',
@ -22,7 +28,12 @@ export function spawn(command, args, opts) {
const nextColor = generateColors();
export function spawnStreaming(command, args, opts, { prefix }) {
export function spawnStreaming(
command: string,
args: string[],
opts: execa.Options,
{ prefix }: { prefix: string }
) {
const spawned = execa(command, args, {
...opts,
stdio: ['ignore', 'pipe', 'pipe'],

View file

@ -1,6 +1,5 @@
export class CliError extends Error {
constructor(message, meta = {}) {
constructor(message: string, public readonly meta = {}) {
super(message);
this.meta = meta;
}
}

View file

@ -1,82 +0,0 @@
import fs from 'fs';
import { relative, dirname } from 'path';
import promisify from 'pify';
import cmdShimCb from 'cmd-shim';
import mkdirpCb from 'mkdirp';
const stat = promisify(fs.stat);
const readFile = promisify(fs.readFile);
const unlink = promisify(fs.unlink);
const symlink = promisify(fs.symlink);
const chmod = promisify(fs.chmod);
const cmdShim = promisify(cmdShimCb);
const mkdirp = promisify(mkdirpCb);
export { chmod, mkdirp, readFile };
async function statTest(path, block) {
try {
return block(await stat(path));
} catch (e) {
if (e.code === 'ENOENT') {
return false;
}
throw e;
}
}
/**
* Test if a path points to a directory
* @param {String} path
* @return {Promise<Boolean>}
*/
export async function isDirectory(path) {
return await statTest(path, stats => stats.isDirectory());
}
/**
* Test if a path points to a regular file
* @param {String} path
* @return {Promise<Boolean>}
*/
export async function isFile(path) {
return await statTest(path, stats => stats.isFile());
}
/**
* Create a symlink at dest that points to src. Adapted from
* https://github.com/lerna/lerna/blob/2f1b87d9e2295f587e4ac74269f714271d8ed428/src/FileSystemUtilities.js#L103
*
* @param {String} src
* @param {String} dest
* @param {String} type 'dir', 'file', 'junction', or 'exec'. 'exec' on
* windows will use the `cmd-shim` module since symlinks can't be used
* for executable files on windows.
* @return {Promise<undefined>}
*/
export async function createSymlink(src, dest, type) {
async function forceCreate(src, dest, type) {
try {
// If something exists at `dest` we need to remove it first.
await unlink(dest);
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
await symlink(src, dest, type);
}
if (process.platform === 'win32') {
if (type === 'exec') {
await cmdShim(src, dest);
} else {
await forceCreate(src, dest, type);
}
} else {
const posixType = type === 'exec' ? 'file' : type;
const relativeSource = relative(dirname(dest), src);
await forceCreate(relativeSource, dest, posixType);
}
}

View file

@ -0,0 +1,101 @@
import fs from 'fs';
import { relative, dirname } from 'path';
import { promisify } from 'bluebird';
import cmdShimCb from 'cmd-shim';
import mkdirpCb from 'mkdirp';
const stat = promisify(fs.stat);
const readFile = promisify(fs.readFile);
const unlink = promisify(fs.unlink);
const symlink = promisify(fs.symlink);
const chmod = promisify(fs.chmod);
const cmdShim = promisify(cmdShimCb);
export { chmod, readFile };
async function statTest(path: string, block: (stats: fs.Stats) => boolean) {
try {
return block(await stat(path));
} catch (e) {
if (e.code === 'ENOENT') {
return false;
}
throw e;
}
}
/**
* Creates the specified directory including any necessary parent directories that don't yet exist.
* @param dir Directory to create.
* @param mode The mode that will be set for directories that need to be created.
* @return Path to he first directory that had to be created, if any.
*/
export function mkdirp(dir: string, mode?: string | number) {
// Custom wrapper around `mkdirp` to provide Promise-based interface. We don't use `promisify`
// function here since it can't automatically infer the right overload and we don't want to expose
// options format used by `mkdirp` directly.
return new Promise<string | null>((resolve, reject) => {
// If mode is provided we can pass it directly, otherwise we should specify empty `options` object.
const options = mode === undefined ? {} : mode;
mkdirpCb(dir, options, (err, args) => {
if (err) {
reject(err);
} else {
resolve(args);
}
});
});
}
/**
* Test if a path points to a directory.
* @param path
*/
export async function isDirectory(path: string) {
return await statTest(path, stats => stats.isDirectory());
}
/**
* Test if a path points to a regular file.
* @param path
*/
export async function isFile(path: string) {
return await statTest(path, stats => stats.isFile());
}
/**
* Create a symlink at dest that points to src. Adapted from
* https://github.com/lerna/lerna/blob/2f1b87d9e2295f587e4ac74269f714271d8ed428/src/FileSystemUtilities.js#L103.
*
* @param src
* @param dest
* @param type 'dir', 'file', 'junction', or 'exec'. 'exec' on
* windows will use the `cmd-shim` module since symlinks can't be used
* for executable files on windows.
*/
export async function createSymlink(src: string, dest: string, type: string) {
if (process.platform === 'win32') {
if (type === 'exec') {
await cmdShim(src, dest);
} else {
await forceCreate(src, dest, type);
}
} else {
const posixType = type === 'exec' ? 'file' : type;
const relativeSource = relative(dirname(dest), src);
await forceCreate(relativeSource, dest, posixType);
}
}
async function forceCreate(src: string, dest: string, type: string) {
try {
// If something exists at `dest` we need to remove it first.
await unlink(dest);
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
await symlink(src, dest, type);
}

View file

@ -1,3 +1,5 @@
jest.mock('./fs');
import { resolve } from 'path';
import {
@ -49,7 +51,7 @@ const projectGraph = buildProjectGraph(projectsByName);
function getFsMockCalls() {
const fs = require('./fs');
const fsMockCalls = {};
const fsMockCalls: { [key: string]: any[][] } = {};
Object.keys(fs).map(key => {
if (jest.isMockFunction(fs[key])) {
fsMockCalls[key] = fs[key].mock.calls;
@ -61,7 +63,6 @@ function getFsMockCalls() {
expect.addSnapshotSerializer(absolutePathSnapshotSerializer);
expect.addSnapshotSerializer(stripAnsiSnapshotSerializer);
jest.mock('./fs');
afterEach(() => {
jest.resetAllMocks();
});

View file

@ -3,6 +3,7 @@ import { resolve, relative, dirname, sep } from 'path';
import chalk from 'chalk';
import { createSymlink, isFile, chmod, mkdirp } from './fs';
import { ProjectGraph, ProjectMap } from './projects';
/**
* Yarn does not link the executables from dependencies that are installed
@ -12,9 +13,12 @@ import { createSymlink, isFile, chmod, mkdirp } from './fs';
* dependencies, and manually linking their executables if defined. The logic
* for linking was mostly adapted from lerna: https://github.com/lerna/lerna/blob/1d7eb9eeff65d5a7de64dea73613b1bf6bfa8d57/src/PackageUtilities.js#L348
*/
export async function linkProjectExecutables(projectsByName, projectGraph) {
export async function linkProjectExecutables(
projectsByName: ProjectMap,
projectGraph: ProjectGraph
) {
for (const [projectName, projectDeps] of projectGraph) {
const project = projectsByName.get(projectName);
const project = projectsByName.get(projectName)!;
const binsDir = resolve(project.nodeModulesLocation, '.bin');
for (const projectDep of projectDeps) {

View file

@ -2,20 +2,25 @@ import readPkg from 'read-pkg';
import writePkg from 'write-pkg';
import path from 'path';
export function readPackageJson(dir) {
export type PackageJson = { [key: string]: any };
export type PackageDependencies = { [key: string]: string };
export type PackageScripts = { [key: string]: string };
export function readPackageJson(dir: string) {
return readPkg(path.join(dir, 'package.json'), { normalize: false });
}
export function writePackageJson(path, json) {
export function writePackageJson(path: string, json: PackageJson) {
return writePkg(path, json);
}
export const createProductionPackageJson = pkgJson => ({
export const createProductionPackageJson = (pkgJson: PackageJson) => ({
...pkgJson,
dependencies: transformDependencies(pkgJson.dependencies),
});
export const isLinkDependency = depVersion => depVersion.startsWith('link:');
export const isLinkDependency = (depVersion: string) =>
depVersion.startsWith('link:');
/**
* Replaces `link:` dependencies with `file:` dependencies. When installing
@ -26,8 +31,8 @@ export const isLinkDependency = depVersion => depVersion.startsWith('link:');
* will then _copy_ the `file:` dependencies into `node_modules` instead of
* symlinking like we do in development.
*/
export function transformDependencies(dependencies = {}) {
const newDeps = {};
export function transformDependencies(dependencies: PackageDependencies = {}) {
const newDeps: PackageDependencies = {};
for (const name of Object.keys(dependencies)) {
const depVersion = dependencies[name];
if (isLinkDependency(depVersion)) {

View file

@ -13,12 +13,12 @@ test('parallelizes batches', async () => {
const baz = createPromiseWithResolve();
const batches = [[foo, bar], [baz]];
const parallelize = parallelizeBatches(batches, obj => {
const parallelize = parallelizeBatches(batches, async obj => {
obj.called = true;
return obj.promise;
await obj.promise;
});
const completed = [];
const completed: string[] = [];
parallelize.then(() => {
completed.push('parallelizeBatches');
});
@ -61,7 +61,9 @@ test('rejects if any promise rejects', async () => {
const baz = createPromiseWithResolve();
const batches = [[foo, bar], [baz]];
const parallelize = parallelizeBatches(batches, obj => obj.promise);
const parallelize = parallelizeBatches(batches, async obj => {
await obj.promise;
});
foo.reject(new Error('foo failed'));
@ -69,11 +71,11 @@ test('rejects if any promise rejects', async () => {
});
function createPromiseWithResolve() {
let resolve;
let reject;
let resolve: (val?: any) => void;
let reject: (err?: any) => void;
const promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
return { promise, resolve, reject, called: false };
return { promise, resolve: resolve!, reject: reject!, called: false };
}

View file

@ -1,4 +1,7 @@
export async function parallelizeBatches(batches, fn) {
export async function parallelizeBatches<T>(
batches: Array<T[]>,
fn: (item: T) => Promise<void>
) {
for (const batch of batches) {
const running = batch.map(obj => fn(obj));

View file

@ -1,15 +1,16 @@
import { resolve, join } from 'path';
import { PackageJson } from './package_json';
import { Project } from './project';
const rootPath = resolve(`${__dirname}/__fixtures__/kibana`);
const createProjectWith = (fields, path = '') =>
const createProjectWith = (packageJson: PackageJson, path = '') =>
new Project(
{
name: 'kibana',
version: '1.0.0',
...fields,
...packageJson,
},
join(rootPath, path)
);

View file

@ -7,16 +7,30 @@ import {
runScriptInPackage,
runScriptInPackageStreaming,
} from './scripts';
import { readPackageJson, isLinkDependency } from './package_json';
import {
PackageJson,
PackageDependencies,
PackageScripts,
isLinkDependency,
readPackageJson,
} from './package_json';
import { CliError } from './errors';
export class Project {
static async fromPath(path) {
static async fromPath(path: string) {
const pkgJson = await readPackageJson(path);
return new Project(pkgJson, path);
}
constructor(packageJson, projectPath) {
public readonly json: PackageJson;
public readonly packageJsonLocation: string;
public readonly nodeModulesLocation: string;
public readonly targetLocation: string;
public readonly path: string;
public readonly allDependencies: PackageDependencies;
public readonly scripts: PackageScripts;
constructor(packageJson: PackageJson, projectPath: string) {
this.json = Object.freeze(packageJson);
this.path = projectPath;
@ -36,7 +50,7 @@ export class Project {
return this.json.name;
}
ensureValidProjectDependency(project) {
ensureValidProjectDependency(project: Project) {
const relativePathToProject = normalizePath(
path.relative(this.path, project.path)
);
@ -77,11 +91,11 @@ export class Project {
return json.kibana && json.kibana.build && json.kibana.build.skip === true;
}
hasScript(name) {
hasScript(name: string) {
return name in this.scripts;
}
getExecutables() {
getExecutables(): { [key: string]: string } {
const raw = this.json.bin;
if (!raw) {
@ -95,7 +109,7 @@ export class Project {
}
if (typeof raw === 'object') {
const binsConfig = {};
const binsConfig: { [k: string]: string } = {};
for (const binName of Object.keys(raw)) {
binsConfig[binName] = path.resolve(this.path, raw[binName]);
}
@ -112,7 +126,7 @@ export class Project {
);
}
async runScript(scriptName, args = []) {
async runScript(scriptName: string, args: string[] = []) {
console.log(
chalk.bold(
`\n\nRunning script [${chalk.green(scriptName)}] in [${chalk.green(
@ -123,7 +137,7 @@ export class Project {
return runScriptInPackage(scriptName, args, this);
}
async runScriptStreaming(scriptName, args = []) {
async runScriptStreaming(scriptName: string, args: string[] = []) {
return runScriptInPackageStreaming(scriptName, args, this);
}
@ -131,7 +145,7 @@ export class Project {
return Object.keys(this.allDependencies).length > 0;
}
async installDependencies({ extraArgs }) {
async installDependencies({ extraArgs }: { extraArgs: string[] }) {
console.log(
chalk.bold(
`\n\nInstalling dependencies in [${chalk.green(this.name)}]:\n`
@ -142,6 +156,6 @@ export class Project {
}
// We normalize all path separators to `/` in generated files
function normalizePath(path) {
function normalizePath(path: string) {
return path.replace(/[\\\/]+/g, '/');
}

View file

@ -5,6 +5,7 @@ import {
buildProjectGraph,
topologicallyBatchProjects,
} from './projects';
import { Project } from './project';
import { getProjectPaths } from '../config';
const rootPath = resolve(`${__dirname}/__fixtures__/kibana`);
@ -77,9 +78,9 @@ describe('#buildProjectGraph', () => {
]);
const graph = buildProjectGraph(projects);
const expected = {};
const expected: { [k: string]: string[] } = {};
for (const [projectName, projects] of graph.entries()) {
expected[projectName] = projects.map(project => project.name);
expected[projectName] = projects.map((project: Project) => project.name);
}
expect(expected).toMatchSnapshot();

View file

@ -1,13 +1,21 @@
import _glob from 'glob';
import path from 'path';
import promisify from 'pify';
import { promisify } from 'bluebird';
import { CliError } from './errors';
import { Project } from './project';
const glob = promisify(_glob);
// Correct overload version of _glob can't be inferred automatically so we
// should explicitly point to the right version with type parameters.
const glob = promisify<string[], string, _glob.IOptions>(_glob);
export async function getProjects(rootPath, projectsPathsPatterns) {
export type ProjectMap = Map<string, Project>;
export type ProjectGraph = Map<string, Project[]>;
export async function getProjects(
rootPath: string,
projectsPathsPatterns: string[]
) {
const projects = new Map();
for (const pattern of projectsPathsPatterns) {
@ -35,7 +43,13 @@ export async function getProjects(rootPath, projectsPathsPatterns) {
return projects;
}
function packagesFromGlobPattern({ pattern, rootPath }) {
function packagesFromGlobPattern({
pattern,
rootPath,
}: {
pattern: string;
rootPath: string;
}) {
const globOptions = {
cwd: rootPath,
@ -56,11 +70,11 @@ function packagesFromGlobPattern({ pattern, rootPath }) {
// https://github.com/isaacs/node-glob/blob/master/common.js#L104
// glob always returns "\\" as "/" in windows, so everyone
// gets normalized because we can't have nice things.
function normalize(dir) {
function normalize(dir: string) {
return path.normalize(dir);
}
export function buildProjectGraph(projects) {
export function buildProjectGraph(projects: ProjectMap) {
const projectGraph = new Map();
for (const project of projects.values()) {
@ -69,7 +83,7 @@ export function buildProjectGraph(projects) {
for (const depName of Object.keys(dependencies)) {
if (projects.has(depName)) {
const dep = projects.get(depName);
const dep = projects.get(depName)!;
project.ensureValidProjectDependency(dep);
@ -83,15 +97,18 @@ export function buildProjectGraph(projects) {
return projectGraph;
}
export function topologicallyBatchProjects(projectsToBatch, projectGraph) {
export function topologicallyBatchProjects(
projectsToBatch: ProjectMap,
projectGraph: ProjectGraph
) {
// We're going to be chopping stuff out of this array, so copy it.
const projects = [...projectsToBatch.values()];
// This maps project names to the number of projects that depend on them.
// As projects are completed their names will be removed from this object.
const refCounts = {};
const refCounts: { [k: string]: number } = {};
projects.forEach(pkg =>
projectGraph.get(pkg.name).forEach(dep => {
projectGraph.get(pkg.name)!.forEach(dep => {
if (!refCounts[dep.name]) refCounts[dep.name] = 0;
refCounts[dep.name]++;
})
@ -102,7 +119,7 @@ export function topologicallyBatchProjects(projectsToBatch, projectGraph) {
// Get all projects that have no remaining dependencies within the repo
// that haven't yet been picked.
const batch = projects.filter(pkg => {
const projectDeps = projectGraph.get(pkg.name);
const projectDeps = projectGraph.get(pkg.name)!;
return projectDeps.filter(dep => refCounts[dep.name] > 0).length === 0;
});

View file

@ -1,10 +1,14 @@
import { spawn, spawnStreaming } from './child_process';
import { yarnPath } from '../paths';
import { Project } from './project';
/**
* Install all dependencies in the given directory
*/
export function installInDir(directory, extraArgs = []) {
export async function installInDir(
directory: string,
extraArgs: string[] = []
) {
const options = [
'install',
'--non-interactive',
@ -14,7 +18,7 @@ export function installInDir(directory, extraArgs = []) {
// We pass the mutex flag to ensure only one instance of yarn runs at any
// given time (e.g. to avoid conflicts).
return spawn(yarnPath, options, {
await spawn(yarnPath, options, {
cwd: directory,
});
}
@ -22,23 +26,31 @@ export function installInDir(directory, extraArgs = []) {
/**
* Run script in the given directory
*/
export function runScriptInPackage(script, args, pkg) {
export async function runScriptInPackage(
script: string,
args: string[],
pkg: Project
) {
const execOpts = {
cwd: pkg.path,
};
return spawn(yarnPath, ['run', script, ...args], execOpts);
await spawn(yarnPath, ['run', script, ...args], execOpts);
}
/**
* Run script in the given directory
*/
export function runScriptInPackageStreaming(script, args, pkg) {
export async function runScriptInPackageStreaming(
script: string,
args: string[],
pkg: Project
) {
const execOpts = {
cwd: pkg.path,
};
return spawnStreaming(yarnPath, ['run', script, ...args], execOpts, {
await spawnStreaming(yarnPath, ['run', script, ...args], execOpts, {
prefix: pkg.name,
});
}

View file

@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"exclude": [
"dist"
],
"include": [
"./src/**/*.ts",
"./types/index.d.ts"
]
}

1
packages/kbn-pm/types/index.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference path="./jest/index.d.ts" />

13
packages/kbn-pm/types/jest/index.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
///<reference types="jest"/>
// Workaround for https://github.com/DefinitelyTyped/DefinitelyTyped/issues/17605.
declare namespace jest {
interface SpyInstance<T> extends Mock<T> {
mockImplementation(fn: (...args: any[]) => any): SpyInstance<T>;
mockImplementationOnce(fn: (...args: any[]) => any): SpyInstance<T>;
mockReturnThis(): SpyInstance<T>;
mockReturnValue(value: any): SpyInstance<T>;
mockReturnValueOnce(value: any): SpyInstance<T>;
mockName(name: string): SpyInstance<T>;
}
}

View file

@ -2,7 +2,7 @@ const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
index: './src/index.ts',
},
target: 'node',
@ -12,14 +12,23 @@ module.exports = {
libraryTarget: 'commonjs2',
},
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
},
test: /\.ts$/,
use: [
{
loader: 'babel-loader',
},
{
loader: 'ts-loader',
},
],
exclude: /node_modules/,
},
// Removing an unnecessary require from
// https://github.com/ForbesLindesay/spawn-sync/blob/8ba6d1bd032917ff5f0cf68508b91bb628d16336/index.js#L3

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@ export default {
...config,
testMatch: [
'**/integration_tests/**/*.test.js',
'**/integration_tests/**/*.test.ts',
],
testPathIgnorePatterns: config.testPathIgnorePatterns.filter(
(pattern) => !pattern.includes('integration_tests')

View file

@ -31,15 +31,23 @@ export default {
coverageReporters: [
'html',
],
globals: {
'ts-jest': {
tsConfigFile: 'src/dev/jest/tsconfig.json',
skipBabel: true,
},
},
moduleFileExtensions: [
'js',
'json',
'ts',
],
modulePathIgnorePatterns: [
'__fixtures__/',
],
testMatch: [
'**/*.test.js',
'**/*.test.ts',
],
testPathIgnorePatterns: [
'<rootDir>/ui_framework/dist/',
@ -50,6 +58,7 @@ export default {
],
transform: {
'^.+\\.js$': '<rootDir>/src/dev/jest/babel_transform.js',
'^.+\\.ts$': 'ts-jest',
},
transformIgnorePatterns: [
'[/\\\\]node_modules[/\\\\].+\\.js$',

View file

@ -0,0 +1,17 @@
{
// Specific changes to TS config needed to run the tests.
"extends": "../../../tsconfig.json",
"compilerOptions": {
"module": "commonjs",
// In production we run the TS output through Babel or Webpack, so we can
// output `esnext` while the tests are ran directly on the TypeScript
// output. We therefore need to the target to match what is available when
// Jest is running. When upgrading Node.js versions we can therefore likely
// update the target to a newer version of EcmaScript.
"target": "es2015"
},
"include": [
"../../../**/*.ts"
]
}

41
tsconfig.json Normal file
View file

@ -0,0 +1,41 @@
{
"compilerOptions": {
// Enables all strict type checking options.
"strict": true,
// Library files to be included in the compilation. Basically which "core
// language features" TypeScript should enable.
"lib": ["es2015", "es2016", "es2017"],
// Which version of EcmaScript TypeScript should transpile to. Because of
// how Babel and Webpack is set up we currently target `esnext`, and let
// Babel take care of transpiling it down.
"target": "esnext",
// Specifies module code generation.
"module": "esnext",
// Allows default imports from modules with no default export. This does not affect code emit, just type checking.
// We have to enable this option explicitly since `esModuleInterop` doesn't enable it automatically when ES2015 or
// ESNext module format is used.
"allowSyntheticDefaultImports": true,
// Emits __importStar and __importDefault helpers for runtime babel ecosystem compatibility.
"esModuleInterop": true,
// Resolve modules in the same way as Node.js. Aka make `require` works the
// same in TypeScript as it does in Node.js.
"moduleResolution": "node",
// Disallow inconsistently-cased references to the same file.
"forceConsistentCasingInFileNames": true,
// Generate an external source map. There's also an `--inlineSourceMap` for
// emitting a single file with source maps instead of having a separate file.
"sourceMap": true
},
"exclude": [
"node_modules"
]
}

260
yarn.lock
View file

@ -118,10 +118,6 @@
version "0.0.0"
uid ""
"@kbn/pm@link:packages/kbn-pm":
version "0.0.0"
uid ""
"@kbn/datemath@link:packages/kbn-datemath":
version "0.0.0"
uid ""
@ -130,6 +126,10 @@
version "0.0.0"
uid ""
"@kbn/pm@link:packages/kbn-pm":
version "0.0.0"
uid ""
"@kbn/test-subj-selector@link:packages/kbn-test-subj-selector":
version "0.0.0"
uid ""
@ -455,6 +455,10 @@ array-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
array-filter@~0.0.0:
version "0.0.1"
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@ -478,10 +482,18 @@ array-includes@^3.0.3:
define-properties "^1.1.2"
es-abstract "^1.7.0"
array-map@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
array-parallel@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/array-parallel/-/array-parallel-0.1.3.tgz#8f785308926ed5aa478c47e64d1b334b6c0c947d"
array-reduce@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
array-series@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/array-series/-/array-series-0.1.5.tgz#df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f"
@ -704,7 +716,7 @@ babel-core@6.21.0:
slash "^1.0.0"
source-map "^0.5.0"
babel-core@^6.0.0, babel-core@^6.0.12, babel-core@^6.18.0, babel-core@^6.26.0:
babel-core@^6.0.0, babel-core@^6.0.12, babel-core@^6.18.0, babel-core@^6.24.1, babel-core@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8"
dependencies:
@ -892,7 +904,7 @@ babel-plugin-check-es2015-constants@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
babel-plugin-istanbul@^4.1.5:
babel-plugin-istanbul@^4.1.4, babel-plugin-istanbul@^4.1.5:
version "4.1.5"
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e"
dependencies:
@ -904,6 +916,10 @@ babel-plugin-jest-hoist@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.0.6.tgz#551269ded350a15d6585da35d16d449df30d66c4"
babel-plugin-jest-hoist@^22.2.0:
version "22.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.2.0.tgz#bd34f39d652406669713b8c89e23ef25c890b993"
babel-plugin-syntax-async-functions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
@ -1247,6 +1263,13 @@ babel-preset-flow@^6.23.0:
dependencies:
babel-plugin-transform-flow-strip-types "^6.22.0"
babel-preset-jest@^22.0.1:
version "22.2.0"
resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.2.0.tgz#f77b43f06ef4d8547214b2e206cc76a25c3ba0e2"
dependencies:
babel-plugin-jest-hoist "^22.2.0"
babel-plugin-syntax-object-rest-spread "^6.13.0"
babel-preset-jest@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.0.6.tgz#d13202533db9495c98663044d9f51b273d3984c8"
@ -1289,7 +1312,7 @@ babel-register@^6.18.0, babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1:
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1, babel-runtime@^6.9.2:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
@ -2553,6 +2576,22 @@ cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
parse-json "^2.2.0"
require-from-string "^1.1.0"
cpx@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f"
dependencies:
babel-runtime "^6.9.2"
chokidar "^1.6.0"
duplexer "^0.1.1"
glob "^7.0.5"
glob2base "^0.0.12"
minimatch "^3.0.2"
mkdirp "^0.5.1"
resolve "^1.1.7"
safe-buffer "^5.0.1"
shell-quote "^1.6.1"
subarg "^1.0.0"
create-ecdh@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
@ -3408,7 +3447,7 @@ duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
duplexer@~0.1.1:
duplexer@^0.1.1, duplexer@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
@ -4241,6 +4280,17 @@ expect@^22.0.6:
jest-message-util "^22.0.6"
jest-regex-util "^22.0.6"
expect@^22.3.0:
version "22.3.0"
resolved "https://registry.yarnpkg.com/expect/-/expect-22.3.0.tgz#b1cb7db27a951ab6055f43937277152a9f668028"
dependencies:
ansi-styles "^3.2.0"
jest-diff "^22.1.0"
jest-get-type "^22.1.0"
jest-matcher-utils "^22.2.0"
jest-message-util "^22.2.0"
jest-regex-util "^22.1.0"
expiry-js@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/expiry-js/-/expiry-js-0.1.7.tgz#76be8c05e572bf936df40c1766448d0b3b2f555f"
@ -4540,6 +4590,10 @@ find-cache-dir@^1.0.0:
make-dir "^1.0.0"
pkg-dir "^2.0.0"
find-index@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
find-root@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-0.1.2.tgz#98d2267cff1916ccaf2743b3a0eea81d79d7dcd1"
@ -4714,6 +4768,14 @@ fs-exists-sync@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
fs-extra@4.0.3, fs-extra@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
@ -4739,14 +4801,6 @@ fs-extra@^3.0.1:
jsonfile "^3.0.0"
universalify "^0.1.0"
fs-extra@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -4936,6 +4990,12 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
glob2base@^0.0.12:
version "0.0.12"
resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
dependencies:
find-index "^0.1.1"
glob@5.0.13:
version "5.0.13"
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f"
@ -6593,6 +6653,22 @@ jest-cli@^22.0.6:
which "^1.2.12"
yargs "^10.0.3"
jest-config@^22.0.1:
version "22.3.0"
resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.3.0.tgz#94c7149f123933a872ee24c1719687419c4a623c"
dependencies:
chalk "^2.0.1"
glob "^7.1.1"
jest-environment-jsdom "^22.3.0"
jest-environment-node "^22.3.0"
jest-get-type "^22.1.0"
jest-jasmine2 "^22.3.0"
jest-regex-util "^22.1.0"
jest-resolve "^22.3.0"
jest-util "^22.3.0"
jest-validate "^22.2.2"
pretty-format "^22.1.0"
jest-config@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.0.6.tgz#8af116784df189b98ed6fd6c307bce4181f7f012"
@ -6618,6 +6694,15 @@ jest-diff@^22.0.6:
jest-get-type "^22.0.6"
pretty-format "^22.0.6"
jest-diff@^22.1.0:
version "22.1.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.1.0.tgz#0fad9d96c87b453896bf939df3dc8aac6919ac38"
dependencies:
chalk "^2.0.1"
diff "^3.2.0"
jest-get-type "^22.1.0"
pretty-format "^22.1.0"
jest-docblock@^21.0.0:
version "21.2.0"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414"
@ -6636,6 +6721,14 @@ jest-environment-jsdom@^22.0.6:
jest-util "^22.0.6"
jsdom "^11.5.1"
jest-environment-jsdom@^22.3.0:
version "22.3.0"
resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.3.0.tgz#c267a063e5dc16219fba0e07542d8aa2576a1c88"
dependencies:
jest-mock "^22.2.0"
jest-util "^22.3.0"
jsdom "^11.5.1"
jest-environment-node@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.0.6.tgz#4f34ac4c0591297aceefa6a93421360bd56e5a74"
@ -6643,10 +6736,21 @@ jest-environment-node@^22.0.6:
jest-mock "^22.0.6"
jest-util "^22.0.6"
jest-environment-node@^22.3.0:
version "22.3.0"
resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.3.0.tgz#97d34d9706a718d743075149d1950555c10338c0"
dependencies:
jest-mock "^22.2.0"
jest-util "^22.3.0"
jest-get-type@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.0.6.tgz#301fbc0760779fdbad37b6e3239a3c1811aa75cb"
jest-get-type@^22.1.0:
version "22.1.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.1.0.tgz#4e90af298ed6181edc85d2da500dbd2753e0d5a9"
jest-haste-map@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.0.6.tgz#198d665f65e1c484fef106a3c970c5b47903647e"
@ -6674,6 +6778,22 @@ jest-jasmine2@^22.0.6:
jest-snapshot "^22.0.6"
source-map-support "^0.5.0"
jest-jasmine2@^22.3.0:
version "22.3.0"
resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.3.0.tgz#ea127dfbb04c6e03998ae0358225435e47520666"
dependencies:
callsites "^2.0.0"
chalk "^2.0.1"
co "^4.6.0"
expect "^22.3.0"
graceful-fs "^4.1.11"
is-generator-fn "^1.0.0"
jest-diff "^22.1.0"
jest-matcher-utils "^22.2.0"
jest-message-util "^22.2.0"
jest-snapshot "^22.2.0"
source-map-support "^0.5.0"
jest-leak-detector@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.0.6.tgz#e983e6fca0959f095cd5b39df2a9a8c956f45988"
@ -6688,6 +6808,14 @@ jest-matcher-utils@^22.0.6:
jest-get-type "^22.0.6"
pretty-format "^22.0.6"
jest-matcher-utils@^22.2.0:
version "22.2.0"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.2.0.tgz#5390f823c18c748543d463825aa8e4df0db253ca"
dependencies:
chalk "^2.0.1"
jest-get-type "^22.1.0"
pretty-format "^22.1.0"
jest-message-util@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.0.6.tgz#2b30edce5131a9358f529ad66ff84835ba4ed457"
@ -6698,14 +6826,32 @@ jest-message-util@^22.0.6:
slash "^1.0.0"
stack-utils "^1.0.1"
jest-message-util@^22.2.0:
version "22.2.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.2.0.tgz#84a6bb34186d8b9af7e0732fabbef63f7355f7b2"
dependencies:
"@babel/code-frame" "^7.0.0-beta.35"
chalk "^2.0.1"
micromatch "^2.3.11"
slash "^1.0.0"
stack-utils "^1.0.1"
jest-mock@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.0.6.tgz#0d1f51ec2bf1e72cd58e79cb76f587e6397306ec"
jest-mock@^22.2.0:
version "22.2.0"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.2.0.tgz#444b3f9488a7473adae09bc8a77294afded397a7"
jest-regex-util@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.0.6.tgz#cd01d33c5993340f5d61be09b270773787a41d88"
jest-regex-util@^22.1.0:
version "22.1.0"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.1.0.tgz#5daf2fe270074b6da63e5d85f1c9acc866768f53"
jest-resolve-dependencies@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.0.6.tgz#dd976f0a9c2874d32edf4876b0a965cef48d479b"
@ -6719,6 +6865,13 @@ jest-resolve@^22.0.6:
browser-resolve "^1.11.2"
chalk "^2.0.1"
jest-resolve@^22.3.0:
version "22.3.0"
resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.3.0.tgz#648e797f708e8701071a0fa9fac652c577bb66d9"
dependencies:
browser-resolve "^1.11.2"
chalk "^2.0.1"
jest-runner@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.0.6.tgz#1986ee82b7968d21f04c402e5b67e3da71496f19"
@ -6768,6 +6921,17 @@ jest-snapshot@^22.0.6:
natural-compare "^1.4.0"
pretty-format "^22.0.6"
jest-snapshot@^22.2.0:
version "22.2.0"
resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.2.0.tgz#0c0ba152d296ef70fa198cc84977a2cc269ee4cf"
dependencies:
chalk "^2.0.1"
jest-diff "^22.1.0"
jest-matcher-utils "^22.2.0"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
pretty-format "^22.1.0"
jest-util@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.0.6.tgz#539b3f21f4e2e458bb38719aa0e417109fe31657"
@ -6780,6 +6944,18 @@ jest-util@^22.0.6:
jest-validate "^22.0.6"
mkdirp "^0.5.1"
jest-util@^22.3.0:
version "22.3.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.3.0.tgz#d05bff567a3a86c0e9b3838d812f8290aa768097"
dependencies:
callsites "^2.0.0"
chalk "^2.0.1"
graceful-fs "^4.1.11"
is-ci "^1.0.10"
jest-message-util "^22.2.0"
jest-validate "^22.2.2"
mkdirp "^0.5.1"
jest-validate@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.0.6.tgz#48c6972f154fa4abe20d0686a9b819d142740167"
@ -6789,6 +6965,15 @@ jest-validate@^22.0.6:
leven "^2.1.0"
pretty-format "^22.0.6"
jest-validate@^22.2.2:
version "22.2.2"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.2.2.tgz#9cdce422c93cc28395e907ac6bbc929158d9a6ba"
dependencies:
chalk "^2.0.1"
jest-get-type "^22.1.0"
leven "^2.1.0"
pretty-format "^22.1.0"
jest-worker@^22.0.6:
version "22.0.6"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.0.6.tgz#1998ac7ab24a6eee4deddec76efe7742f2651504"
@ -9582,6 +9767,13 @@ pretty-format@^22.0.6:
ansi-regex "^3.0.0"
ansi-styles "^3.2.0"
pretty-format@^22.1.0:
version "22.1.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.1.0.tgz#2277605b40ed4529ae4db51ff62f4be817647914"
dependencies:
ansi-regex "^3.0.0"
ansi-styles "^3.2.0"
prismjs@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-0.0.1.tgz#0fd50f4baf26e5cd33523b65bac2f0bc90f5503f"
@ -10533,7 +10725,7 @@ resolve@1.1.7, resolve@1.1.x, resolve@~1.1.0, resolve@~1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
resolve@^1.1.6, resolve@^1.2.0, resolve@^1.5.0:
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
dependencies:
@ -10934,6 +11126,15 @@ shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
shell-quote@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
dependencies:
array-filter "~0.0.0"
array-map "~0.0.0"
array-reduce "~0.0.0"
jsonify "~0.0.0"
shelljs@^0.7.0, shelljs@^0.7.5:
version "0.7.8"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
@ -11477,6 +11678,12 @@ style-loader@0.19.0:
loader-utils "^1.0.2"
schema-utils "^0.3.0"
subarg@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2"
dependencies:
minimist "^1.1.0"
subtext@4.x.x:
version "4.4.1"
resolved "https://registry.yarnpkg.com/subtext/-/subtext-4.4.1.tgz#2fcec945de429283c3d18b151ff0fa1f1b87aec9"
@ -11942,6 +12149,21 @@ trunc-text@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/trunc-text/-/trunc-text-1.0.2.tgz#b582bb3ddea9c9adc25017d737c48ebdd2157406"
ts-jest@^22.0.4:
version "22.0.4"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-22.0.4.tgz#be5e8d7d2cf3f3ef97d877a6a0562508c3f64515"
dependencies:
babel-core "^6.24.1"
babel-plugin-istanbul "^4.1.4"
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
babel-preset-jest "^22.0.1"
cpx "^1.5.0"
fs-extra "4.0.3"
jest-config "^22.0.1"
pkg-dir "^2.0.0"
source-map-support "^0.5.0"
yargs "^11.0.0"
tslib@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
@ -12002,6 +12224,10 @@ typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
typescript@^2.7.2:
version "2.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
ua-parser-js@^0.7.9:
version "0.7.17"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac"