[Code] use isomorphic-git to handle git references (#40951) (#40998)

* [Code] use isomorphic-git to read git references
This commit is contained in:
Yulong 2019-07-12 23:53:06 +08:00 committed by GitHub
parent 77e14c373c
commit ca5f953581
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 411 additions and 189 deletions

View file

@ -79,7 +79,8 @@
"resolutions": {
"**/@types/node": "10.12.27",
"**/@types/hapi": "^17.0.18",
"**/typescript": "3.5.3"
"**/typescript": "3.5.3",
"**/isomorphic-git/**/base64-js": "^1.2.1"
},
"workspaces": {
"packages": [

View file

@ -8,6 +8,7 @@ export interface CommitInfo {
updated: Date;
message: string;
committer: string;
author: string;
id: string;
parents: string[];
}

View file

@ -39,6 +39,7 @@ function prepareProject(url: string, p: string) {
certificateCheck: () => 0,
},
},
bare: 1,
}).then(repo => {
resolve(repo);
});

View file

@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
// @ts-ignore
import Git from '@elastic/nodegit';
import assert from 'assert';
import { execSync } from 'child_process';
@ -34,8 +35,12 @@ describe('git_operations', () => {
try {
const g = new GitOperations(serverOptions.repoPath);
const defaultBranch = await g.getDefaultBranch(repoUri);
const uri = path.join(repoUri, '.git');
const defaultBranch = await g.getDefaultBranch(uri);
assert.strictEqual(defaultBranch, 'trunk');
const headRevision = await g.getHeadRevision(uri);
const headCommit = await g.getCommitInfo(uri, 'HEAD');
assert.strictEqual(headRevision, headCommit!.id);
} finally {
rimraf.sync(repoDir);
}
@ -43,13 +48,14 @@ describe('git_operations', () => {
async function prepareProject(repoPath: string) {
mkdirp.sync(repoPath);
const repo = await Git.Repository.init(repoPath, 0);
const workDir = path.join(serverOptions.workspacePath, repoUri);
const repo = await Git.Repository.init(workDir, 0);
const content = '';
fs.writeFileSync(path.join(repo.workdir(), '1'), content, 'utf8');
fs.writeFileSync(path.join(workDir, '1'), content, 'utf8');
const subFolder = 'src';
fs.mkdirSync(path.join(repo.workdir(), subFolder));
fs.writeFileSync(path.join(repo.workdir(), 'src/2'), content, 'utf8');
fs.writeFileSync(path.join(repo.workdir(), 'src/3'), content, 'utf8');
fs.mkdirSync(path.join(workDir, subFolder));
fs.writeFileSync(path.join(workDir, 'src/2'), content, 'utf8');
fs.writeFileSync(path.join(workDir, 'src/3'), content, 'utf8');
const index = await repo.refreshIndex();
await index.addByPath('1');
@ -68,12 +74,19 @@ describe('git_operations', () => {
);
// eslint-disable-next-line no-console
console.log(`created commit ${commit.tostrS()}`);
return repo;
await Git.Clone.clone(workDir, repoPath, { bare: 1 });
return Git.Repository.openBare(repoPath);
}
// @ts-ignore
before(async () => {
before(async function() {
// @ts-ignore
this.timeout(200000);
await prepareProject(path.join(serverOptions.repoPath, repoUri));
await cloneProject(
'https://github.com/elastic/TypeScript-Node-Starter.git',
path.join(serverOptions.repoPath, 'github.com/elastic/TypeScript-Node-Starter')
);
});
const repoUri = 'github.com/test/test_repo';
@ -94,47 +107,47 @@ describe('git_operations', () => {
assert.strictEqual('3', value.name);
assert.strictEqual('src/3', value.path);
} else {
assert.fail('this repo should contains exactly 2 files');
assert.fail('this repo should contains exactly 3 files');
}
count++;
}
const totalFiles = await g.countRepoFiles(repoUri, 'HEAD');
assert.strictEqual(count, 3, 'this repo should contains exactly 2 files');
assert.strictEqual(totalFiles, 3, 'this repo should contains exactly 2 files');
assert.strictEqual(count, 3, 'this repo should contains exactly 3 files');
assert.strictEqual(totalFiles, 3, 'this repo should contains exactly 3 files');
});
function cloneProject(url: string, p: string) {
return new Promise(resolve => {
if (!fs.existsSync(p)) {
rimraf(p, error => {
Git.Clone.clone(url, p, {
bare: 1,
fetchOpts: {
callbacks: {
certificateCheck: () => 0,
},
},
}).then(repo => {
resolve(repo);
});
});
} else {
resolve();
}
});
}
it('can resolve branches', async () => {
const g = new GitOperations(serverOptions.repoPath);
const c = await g.getCommitOr404('github.com/elastic/TypeScript-Node-Starter', 'master');
assert.strictEqual(c.id, '261557d657fdfddf78119d15d38b1f6a7be005ed');
const c1 = await g.getCommitOr404('github.com/elastic/TypeScript-Node-Starter', 'VS');
assert.strictEqual(c1.id, 'ba73782df210e0a7744ac9b623d58081a1801738');
// @ts-ignore
}).timeout(100000);
it('get diff between arbitrary 2 revisions', async () => {
function cloneProject(url: string, p: string) {
return new Promise(resolve => {
if (!fs.existsSync(p)) {
rimraf(p, error => {
Git.Clone.clone(url, p, {
fetchOpts: {
callbacks: {
certificateCheck: () => 0,
},
},
}).then(repo => {
resolve(repo);
});
});
} else {
resolve();
}
});
}
await cloneProject(
'https://github.com/Microsoft/TypeScript-Node-Starter.git',
path.join(serverOptions.repoPath, 'github.com/Microsoft/TypeScript-Node-Starter')
);
const g = new GitOperations(serverOptions.repoPath);
const d = await g.getDiff(
'github.com/Microsoft/TypeScript-Node-Starter',
'6206f643',
'4779cb7e'
);
const d = await g.getDiff('github.com/elastic/TypeScript-Node-Starter', '6206f643', '4779cb7e');
assert.equal(d.additions, 2);
assert.equal(d.deletions, 4);
assert.equal(d.files.length, 3);

View file

@ -338,7 +338,7 @@ describe('lsp_indexer unit tests', function(this: any) {
for (let i = 0; i < bulkSpy.callCount; i++) {
total += bulkSpy.getCall(i).args[0].body.length;
}
assert.strictEqual(total, 48 * 2);
assert.strictEqual(total, 49 * 2);
// @ts-ignore
}).timeout(20000);
});

View file

@ -11,9 +11,7 @@ import {
Commit,
Diff as NodeGitDiff,
Error as NodeGitError,
Object,
Oid,
Reference,
Repository,
Tree,
TreeEntry,
@ -22,6 +20,9 @@ import Boom from 'boom';
import LruCache from 'lru-cache';
import * as Path from 'path';
import * as fs from 'fs';
import * as isogit from 'isomorphic-git';
import { CommitDescription, TreeDescription } from 'isomorphic-git';
import { isBinaryFileSync } from 'isbinaryfile';
import { GitBlame } from '../common/git_blame';
import { CommitDiff, Diff, DiffKind } from '../common/git_diff';
@ -29,6 +30,8 @@ import { FileTree, FileTreeItemType, RepositoryUri, sortFileTree } from '../mode
import { CommitInfo, ReferenceInfo, ReferenceType } from '../model/commit';
import { detectLanguage } from './utils/detect_language';
isogit.plugins.set('fs', fs);
export const HEAD = 'HEAD';
const REFS_HEADS = 'refs/heads/';
export const DEFAULT_TREE_CHILDREN_LIMIT = 50;
@ -115,49 +118,51 @@ export class GitOperations {
}
public async fileContent(uri: RepositoryUri, path: string, revision: string = 'master') {
const commit = await this.getCommit(uri, revision);
const entry: TreeEntry = await checkExists(
() => commit.getEntry(path),
`file ${uri}/${path} not found `
);
if (entry.isFile() || entry.filemode() === TreeEntry.FILEMODE.LINK) {
return await entry.getBlob();
} else {
throw Boom.unsupportedMediaType(`${uri}/${path} is not a file.`);
const gitdir = this.repoDir(uri);
const commit: CommitInfo = await this.getCommitOr404(uri, revision);
const file = await isogit.readObject({
gitdir,
oid: commit.id,
filepath: path,
format: 'content',
});
if (file && file.type === 'blob') {
return {
isBinary() {
return isBinaryFileSync(file.object as Buffer);
},
content() {
return file.object as Buffer;
},
rawsize() {
return (file.object as Buffer).length;
},
};
}
throw Boom.unsupportedMediaType(`${uri}/${path} is not a file.`);
}
public async getCommit(uri: RepositoryUri, revision: string): Promise<Commit> {
const info = await this.getCommitOr404(uri, revision);
const repo = await this.openRepo(uri);
if (revision.toUpperCase() === HEAD) {
return await repo.getHeadCommit();
}
// branches and tags
const refs = [`refs/remotes/origin/${revision}`, `refs/tags/${revision}`];
const commit = await this.findCommitByRefs(repo, refs);
if (commit === null) {
return (await checkExists(
() => this.findCommit(repo, revision),
`revision or branch ${revision} not found in ${repo.path()}`
)) as Commit;
}
return commit;
return (await checkExists(
() => this.findCommit(repo, info.id),
`revision or branch ${revision} not found in ${uri}`
)) as Commit;
}
public async getDefaultBranch(uri: RepositoryUri): Promise<string> {
const repo = await this.openRepo(uri);
const ref = await repo.getReference(HEAD);
const name = ref.name();
if (name.startsWith(REFS_HEADS)) {
return name.substr(REFS_HEADS.length);
const gitdir = this.repoDir(uri);
const ref = await isogit.resolveRef({ gitdir, ref: HEAD, depth: 2 });
if (ref.startsWith(REFS_HEADS)) {
return ref.substr(REFS_HEADS.length);
}
return name;
return ref;
}
public async getHeadRevision(uri: RepositoryUri): Promise<string> {
const repo = await this.openRepo(uri);
const commit = await repo.getHeadCommit();
return commit.sha();
const gitdir = this.repoDir(uri);
return await isogit.resolveRef({ gitdir, ref: HEAD, depth: 10 });
}
public async blame(uri: RepositoryUri, revision: string, path: string): Promise<GitBlame[]> {
@ -196,8 +201,7 @@ export class GitOperations {
return Promise.resolve(repo);
}
const repoDir = Path.join(this.repoRoot, uri);
this.checkPath(repoDir);
const repoDir = this.repoDir(uri);
const repo = await checkExists<Repository>(
() => Repository.open(repoDir),
`repo ${uri} not found`
@ -206,30 +210,43 @@ export class GitOperations {
return Promise.resolve(repo);
}
private repoDir(uri: RepositoryUri) {
const repoDir = Path.join(this.repoRoot, uri);
this.checkPath(repoDir);
return repoDir;
}
private checkPath(path: string) {
if (!fs.realpathSync(path).startsWith(fs.realpathSync(this.repoRoot))) {
throw new Error('invalid path');
}
}
public async countRepoFiles(uri: RepositoryUri, revision: string): Promise<number> {
const commit = await this.getCommit(uri, revision);
const tree = await commit.getTree();
let count = 0;
const commit = await this.getCommitOr404(uri, revision);
const gitdir = this.repoDir(uri);
const commitObject = await isogit.readObject({ gitdir, oid: commit.id });
const treeId = (commitObject.object as CommitDescription).tree;
async function walk(t: Tree) {
for (const e of t.entries()) {
if (e.isFile() && e.filemode() !== TreeEntry.FILEMODE.LINK) {
count++;
} else if (e.isDirectory()) {
const subFolder = await e.getTree();
await walk(subFolder);
} else {
// ignore other files
async function walk(oid: string) {
const { object } = await isogit.readObject({ gitdir, oid });
const tree = object as TreeDescription;
for (const entry of tree.entries) {
if (entry.type === 'tree') {
await walk(entry.oid);
} else if (entry.type === 'blob') {
const type = GitOperations.mode2type(entry.mode);
if (type === FileTreeItemType.File) {
const blob = await isogit.readObject({ gitdir, oid: entry.oid, format: 'content' });
if (!isBinaryFileSync(blob.object as Buffer)) {
count++;
}
}
}
}
}
await walk(tree);
await walk(treeId);
return count;
}
@ -237,27 +254,53 @@ export class GitOperations {
uri: RepositoryUri,
revision: string
): Promise<AsyncIterableIterator<FileTree>> {
const commit = await this.getCommit(uri, revision);
const tree = await commit.getTree();
async function* walk(t: Tree): AsyncIterableIterator<FileTree> {
for (const e of t.entries()) {
if (e.isFile() && e.filemode() !== TreeEntry.FILEMODE.LINK) {
const blob = await e.getBlob();
// Ignore binary files
if (!blob.isBinary()) {
yield entry2Tree(e);
async function* walk(oid: string, prefix: string = ''): AsyncIterableIterator<FileTree> {
const { object } = await isogit.readObject({ gitdir, oid });
const tree = object as TreeDescription;
for (const entry of tree.entries) {
const path = prefix ? `${prefix}/${entry.path}` : entry.path;
if (entry.type === 'tree') {
yield* walk(entry.oid, path);
} else if (entry.type === 'blob') {
const type = GitOperations.mode2type(entry.mode);
if (type === FileTreeItemType.File) {
const blob = await isogit.readObject({ gitdir, oid: entry.oid, format: 'content' });
if (!isBinaryFileSync(blob.object as Buffer)) {
yield {
name: entry.path,
type,
path,
repoUri: uri,
sha1: entry.oid,
} as FileTree;
}
}
} else if (e.isDirectory()) {
const subFolder = await e.getTree();
await (yield* walk(subFolder));
} else {
// ignore other files
}
}
}
return await walk(tree);
const commit = await this.getCommitOr404(uri, revision);
const gitdir = this.repoDir(uri);
const commitObject = await isogit.readObject({ gitdir, oid: commit.id });
const treeId = (commitObject.object as CommitDescription).tree;
return await walk(treeId);
}
static mode2type(mode: string): FileTreeItemType {
switch (mode) {
case '100755':
case '100644':
return FileTreeItemType.File;
case '120000':
return FileTreeItemType.Link;
case '40000':
case '040000':
return FileTreeItemType.Directory;
case '160000':
return FileTreeItemType.Submodule;
default:
throw new Error('unknown mode: ' + mode);
}
}
/**
@ -269,6 +312,7 @@ export class GitOperations {
* @param limit pagination parameter, limit the number of node's children.
* @param resolveParents whether the return value should always start from root
* @param childrenDepth how depth should the children walk.
* @param flatten
*/
public async fileTree(
uri: RepositoryUri,
@ -539,37 +583,107 @@ export class GitOperations {
return fileTree;
}
private async findCommit(repo: Repository, revision: string): Promise<Commit | null> {
private async findCommit(repo: Repository, oid: string): Promise<Commit | null> {
try {
const obj = await Object.lookupPrefix(
repo,
Oid.fromString(revision),
revision.length,
Object.TYPE.COMMIT
);
if (obj) {
return repo.getCommit(obj.id());
}
return null;
return repo.getCommit(Oid.fromString(oid));
} catch (e) {
return null;
}
}
private async findCommitByRefs(repo: Repository, refs: string[]): Promise<Commit | null> {
if (refs.length === 0) {
return null;
}
const [ref, ...rest] = refs;
try {
return await repo.getReferenceCommit(ref);
} catch (e) {
if (e.errno === NodeGitError.CODE.ENOTFOUND) {
return await this.findCommitByRefs(repo, rest);
} else {
throw e;
public async getBranchAndTags(repoUri: string): Promise<ReferenceInfo[]> {
const gitdir = this.repoDir(repoUri);
const remoteBranches = await isogit.listBranches({ gitdir, remote: 'origin' });
const results: ReferenceInfo[] = [];
for (const name of remoteBranches) {
const reference = `refs/remotes/origin/${name}`;
const commit = await this.getCommitInfo(repoUri, reference);
if (commit) {
results.push({
name,
reference,
type: ReferenceType.REMOTE_BRANCH,
commit,
});
}
}
const tags = await isogit.listTags({ gitdir });
for (const name of tags) {
const reference = `refs/tags/${name}`;
const commit = await this.getCommitInfo(repoUri, reference);
if (commit) {
results.push({
name,
reference,
type: ReferenceType.TAG,
commit,
});
}
}
return results;
}
public async getCommitOr404(repoUri: string, ref: string): Promise<CommitInfo> {
const commit = await this.getCommitInfo(repoUri, ref);
if (!commit) {
throw Boom.notFound(`repo ${repoUri} or ${ref} not found`);
}
return commit;
}
public async getCommitInfo(repoUri: string, ref: string): Promise<CommitInfo | null> {
const gitdir = this.repoDir(repoUri);
// depth: avoid infinite loop
let obj: isogit.GitObjectDescription | null = null;
let oid: string = '';
if (/^[0-9a-f]{5,40}$/.test(ref)) {
// it's possible ref is sha-1 object id
try {
oid = ref;
if (oid.length < 40) {
oid = await isogit.expandOid({ gitdir, oid });
}
obj = await isogit.readObject({ gitdir, oid, format: 'parsed' });
} catch (e) {
// expandOid or readObject failed
}
}
// test if it is a reference
if (!obj) {
try {
// try local branches or tags
oid = await isogit.resolveRef({ gitdir, ref, depth: 10 });
} catch (e) {
// try remote branches
try {
oid = await isogit.resolveRef({ gitdir, ref: `origin/${ref}`, depth: 10 });
} catch (e1) {
// no match
}
}
if (oid) {
obj = await isogit.readObject({ gitdir, oid, format: 'parsed' });
}
}
if (obj) {
if (obj.type === 'commit') {
const commit = obj.object as isogit.CommitDescription;
return {
id: obj.oid,
author: commit.author.name,
committer: commit.committer.name,
message: commit.message,
updated: new Date(commit.committer.timestamp * 1000),
parents: commit.parent,
} as CommitInfo;
} else if (obj.type === 'tag') {
const tag = obj.object as isogit.TagDescription;
if (tag.type === 'commit') {
return await this.getCommitInfo(repoUri, tag.object);
}
}
}
return null;
}
}
@ -577,40 +691,9 @@ export function commitInfo(commit: Commit): CommitInfo {
return {
updated: commit.date(),
message: commit.message(),
author: commit.author().name(),
committer: commit.committer().name(),
id: commit.sha().substr(0, 7),
parents: commit.parents().map(oid => oid.toString().substring(0, 7)),
};
}
const REMOTE_PREFIX = 'origin/';
export async function referenceInfo(ref: Reference): Promise<ReferenceInfo | null> {
const repository = ref.owner();
let commit: CommitInfo | undefined;
try {
const object = await ref.peel(Object.TYPE.COMMIT);
commit = commitInfo(await repository.getCommit(object.id()));
} catch {
return null;
}
let type: ReferenceType;
let name = ref.shorthand();
if (ref.isTag()) {
type = ReferenceType.TAG;
} else if (ref.isRemote()) {
if (name.startsWith(REMOTE_PREFIX)) {
name = name.substr(REMOTE_PREFIX.length);
}
type = ReferenceType.REMOTE_BRANCH;
} else if (ref.isBranch()) {
type = ReferenceType.BRANCH;
} else {
type = ReferenceType.OTHER;
}
return {
name,
reference: ref.name(),
commit,
type,
};
}

View file

@ -4,23 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Commit, Reference, Revwalk } from '@elastic/nodegit';
import { Commit, Oid, Revwalk } from '@elastic/nodegit';
import Boom from 'boom';
import fileType from 'file-type';
import hapi, { RequestQuery } from 'hapi';
import {
commitInfo,
DEFAULT_TREE_CHILDREN_LIMIT,
GitOperations,
referenceInfo,
} from '../git_operations';
import { commitInfo, DEFAULT_TREE_CHILDREN_LIMIT, GitOperations } from '../git_operations';
import { extractLines } from '../utils/buffer';
import { detectLanguage } from '../utils/detect_language';
import { CodeServerRouter } from '../security';
import { RepositoryObjectClient } from '../search';
import { EsClientWithRequest } from '../utils/esclient_with_request';
import { TEXT_FILE_LIMIT } from '../../common/file';
import { ReferenceType } from '../../model/commit';
import { decodeRevisionString } from '../../common/uri_util';
export function fileRoute(server: CodeServerRouter, gitOps: GitOperations) {
@ -178,21 +172,24 @@ export function fileRoute(server: CodeServerRouter, gitOps: GitOperations) {
return Boom.notFound(`repo ${uri} not found`);
}
const repository = await gitOps.openRepo(uri);
const commit = await gitOps.getCommit(uri, revision);
const commit = await gitOps.getCommitInfo(uri, revision);
if (commit === null) {
throw Boom.notFound(`commit ${revision} not found in repo ${uri}`);
}
const walk = repository.createRevWalk();
walk.sorting(Revwalk.SORT.TIME);
walk.push(commit.id());
const commitId = Oid.fromString(commit!.id);
walk.push(commitId);
let commits: Commit[];
if (path) {
// magic number 10000: how many commits at the most to iterate in order to find the commits contains the path
const results = await walk.fileHistoryWalk(path, count, 10000);
commits = results.map(result => result.commit);
} else {
walk.push(commit.id());
commits = await walk.getCommits(count);
}
if (after && commits.length > 0) {
if (commits[0].id().equal(commit.id())) {
if (commits[0].id().equal(commitId)) {
commits = commits.slice(1);
}
}
@ -215,14 +212,7 @@ export function fileRoute(server: CodeServerRouter, gitOps: GitOperations) {
return Boom.notFound(`repo ${uri} not found`);
}
try {
const repository = await gitOps.openRepo(uri);
const references = await repository.getReferences(Reference.TYPE.DIRECT);
const referenceInfos = await Promise.all(references.map(referenceInfo));
return referenceInfos.filter(
info =>
info !== null &&
(info.type === ReferenceType.REMOTE_BRANCH || info.type === ReferenceType.TAG)
);
return await gitOps.getBranchAndTags(uri);
} catch (e) {
if (e.isBoom) {
return e;

View file

@ -102,6 +102,7 @@
"ansi-colors": "^3.0.5",
"ansicolors": "0.3.2",
"axios": "^0.19.0",
"base64-js": "^1.2.1",
"babel-jest": "^24.1.0",
"babel-plugin-inline-react-svg": "1.1.0",
"babel-plugin-mock-imports": "1.0.1",
@ -203,7 +204,6 @@
"apollo-server-errors": "^2.0.2",
"apollo-server-hapi": "^1.3.6",
"axios": "^0.19.0",
"base64-js": "^1.2.1",
"bluebird": "3.5.5",
"boom": "^7.2.0",
"brace": "0.11.1",
@ -248,6 +248,8 @@
"immer": "^1.5.0",
"inline-style": "^2.0.0",
"intl": "^1.2.5",
"isomorphic-git": "0.55.5",
"isbinaryfile": "4.0.2",
"io-ts": "^1.4.2",
"joi": "^13.5.2",
"jquery": "^3.4.1",

145
yarn.lock
View file

@ -5962,6 +5962,11 @@ async-limiter@~1.0.0:
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
async-lock@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.2.0.tgz#cd6a53cb1ec3f86af25eafdeb6bc7c6e317258b8"
integrity sha512-81HzTQm4+qMj6PwNlnR+y9g7pDdGGzd/YBUrQnHk+BhR28ja2qv497NkQQc1KcKEqh/RShm07di2b0cIWVFrNQ==
async-retry@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.2.3.tgz#a6521f338358d322b1a0012b79030c6f411d1ce0"
@ -6757,6 +6762,11 @@ base64-arraybuffer@0.1.5:
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
base64-js@0.0.2, base64-js@^1.2.1, base64-js@^1.2.3:
version "1.3.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
base64-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
@ -6767,11 +6777,6 @@ base64-js@^1.0.2, base64-js@^1.1.2:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
integrity sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==
base64-js@^1.2.1, base64-js@^1.2.3:
version "1.3.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
base64id@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
@ -7060,6 +7065,14 @@ boom@7.x.x, boom@^7.1.0, boom@^7.2.0:
dependencies:
hoek "6.x.x"
bops@~0.0.6:
version "0.0.7"
resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.7.tgz#b4a0a5a839a406454af0fe05a8b91a7a766a54e2"
integrity sha1-tKClqDmkBkVK8P4FqLkaenZqVOI=
dependencies:
base64-js "0.0.2"
to-utf8 "0.0.1"
bottleneck@^2.15.3:
version "2.18.0"
resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.18.0.tgz#41fa63ae185b65435d789d1700334bc48222dacf"
@ -8138,6 +8151,11 @@ clean-css@4.2.x, clean-css@^4.1.11:
dependencies:
source-map "~0.6.0"
clean-git-ref@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/clean-git-ref/-/clean-git-ref-1.0.3.tgz#5325dc839eab01c974ae0e97f5734782750f88ec"
integrity sha1-UyXcg56rAcl0rg6X9XNHgnUPiOw=
clean-stack@^1.0.0, clean-stack@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31"
@ -9076,6 +9094,14 @@ cpy@^7.0.1:
globby "^8.0.1"
nested-error-stacks "^2.0.0"
crc-32@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208"
integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==
dependencies:
exit-on-epipe "~1.0.1"
printj "~1.1.0"
crc32-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4"
@ -10394,6 +10420,13 @@ diagnostics@^1.1.1:
enabled "1.0.x"
kuler "1.0.x"
diff-lines@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/diff-lines/-/diff-lines-1.1.1.tgz#4f10a709b6ce2af1d6b412ada5a90cf01d782571"
integrity sha512-Oo5JzEEriF/+T0usOeRP5yOzr6SWvni2rrxvIgijMZSxPcEvf8JOvCO5GpnWwkte7fcOgnue/f5ECg1H9lMPCw==
dependencies:
diff "^3.5.0"
diff-sequences@^24.0.0:
version "24.0.0"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.0.0.tgz#cdf8e27ed20d8b8d3caccb4e0c0d8fe31a173013"
@ -11922,6 +11955,11 @@ exit-hook@^2.1.0:
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-2.1.0.tgz#2be08d8d01220050878577bfa017e104a6c3bcf3"
integrity sha512-JCSm9Znc/KW6hoKYHOIqLxM2Z88+AQcabo07rJHZSyXcQIq6HsXkSWRVZRp13RFkGVIDcz1DRIbKR5cnU1uzCA==
exit-on-epipe@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==
exit@^0.1.2, exit@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@ -13388,6 +13426,14 @@ gh-got@^5.0.0:
got "^6.2.0"
is-plain-obj "^1.1.0"
git-apply-delta@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/git-apply-delta/-/git-apply-delta-0.0.7.tgz#fb76ae144540d79440b52b31de03e63c993c7219"
integrity sha1-+3auFEVA15RAtSsx3gPmPJk8chk=
dependencies:
bops "~0.0.6"
varint "0.0.3"
git-clone@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/git-clone/-/git-clone-0.1.0.tgz#0d76163778093aef7f1c30238f2a9ef3f07a2eb9"
@ -13692,6 +13738,11 @@ globals@^9.18.0, globals@^9.2.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
globalyzer@^0.1.0:
version "0.1.4"
resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.4.tgz#bc8e273afe1ac7c24eea8def5b802340c5cc534f"
integrity sha512-LeguVWaxgHN0MNbWC6YljNMzHkrCny9fzjmEUdnF1kQ7wATFD1RHFRqA1qxaX2tgxGENlcxjOflopBwj3YZiXA==
globby@8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d"
@ -13779,6 +13830,11 @@ globby@^9.2.0:
pify "^4.0.1"
slash "^2.0.0"
globrex@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098"
integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==
globule@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
@ -15182,7 +15238,7 @@ ignore@^4.0.3, ignore@^4.0.6:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.1.1:
ignore@^5.0.4, ignore@^5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.2.tgz#e28e584d43ad7e92f96995019cc43b9e1ac49558"
integrity sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==
@ -16341,6 +16397,11 @@ isarray@2.0.1:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
isbinaryfile@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.2.tgz#bfc45642da645681c610cca831022e30af426488"
integrity sha512-C3FSxJdNrEr2F4z6uFtNzECDM5hXk+46fxaa+cwBe5/XrWSmzdG8DDgyjfX6/NRdBB21q2JXuRAzPCUs+fclnQ==
isbinaryfile@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621"
@ -16383,6 +16444,27 @@ isomorphic-fetch@^2.1.1:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
isomorphic-git@0.55.5:
version "0.55.5"
resolved "https://registry.yarnpkg.com/isomorphic-git/-/isomorphic-git-0.55.5.tgz#d232dddefa9d271470b9b496c14aa65aa98f2519"
integrity sha512-qqFID4DYGjnMkxDowXbp5GUdId6SJCbOEZFRdodMgrk26hjeOiNiOpGlYOX4rBe2mJAsE7Bdj30EQAQJtE72DA==
dependencies:
async-lock "^1.1.0"
clean-git-ref "1.0.3"
crc-32 "^1.2.0"
diff-lines "^1.1.1"
git-apply-delta "0.0.7"
globalyzer "^0.1.0"
globrex "^0.1.2"
ignore "^5.0.4"
marky "^1.2.1"
minimisted "^2.0.0"
pako "^1.0.10"
pify "^4.0.1"
readable-stream "^3.1.1"
sha.js "^2.4.9"
simple-get "^3.0.2"
isstream@0.1.x, isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@ -18940,6 +19022,11 @@ marksy@^6.1.0:
he "^1.1.1"
marked "^0.3.12"
marky@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02"
integrity sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==
material-colors@^1.2.1:
version "1.2.5"
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.5.tgz#5292593e6754cb1bcc2b98030e4e0d6a3afc9ea1"
@ -19370,6 +19457,13 @@ minimist@~0.0.1:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
minimisted@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/minimisted/-/minimisted-2.0.0.tgz#5e3295e74ed701b1cbeaa863a888181d6efbe8ce"
integrity sha512-oP88Dw3LK/pdrKyMdlbmg3W50969UNr4ctISzJfPl+YPYHTAOrS+dihXnsgRNKSRIzDsrnV3eE2CCVlZbpOKdQ==
dependencies:
minimist "^1.2.0"
minimost@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/minimost/-/minimost-1.0.0.tgz#1d07954aa0268873408b95552fbffc5977dfc78b"
@ -20993,7 +21087,7 @@ pako@^0.2.5:
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
pako@^1.0.5, pako@~1.0.2:
pako@^1.0.10, pako@^1.0.5, pako@~1.0.2:
version "1.0.10"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
@ -21914,6 +22008,11 @@ pretty-ms@^4.0.0:
dependencies:
parse-ms "^2.0.0"
printj@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
prismjs@^1.8.4, prismjs@~1.16.0:
version "1.16.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.16.0.tgz#406eb2c8aacb0f5f0f1167930cb83835d10a4308"
@ -25178,6 +25277,14 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
sha.js@^2.4.9:
version "2.4.11"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
shallow-clone@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060"
@ -25287,6 +25394,20 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
simple-concat@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=
simple-get@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.0.3.tgz#924528ac3f9d7718ce5e9ec1b1a69c0be4d62efa"
integrity sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==
dependencies:
decompress-response "^3.3.0"
once "^1.3.1"
simple-concat "^1.0.0"
simple-git@1.116.0:
version "1.116.0"
resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.116.0.tgz#ea6e533466f1e0152186e306e004d4eefa6e3e00"
@ -27091,6 +27212,11 @@ to-through@^2.0.0:
dependencies:
through2 "^2.0.3"
to-utf8@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852"
integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI=
toggle-selection@^1.0.3:
version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
@ -28453,6 +28579,11 @@ value-or-function@^3.0.0:
resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
varint@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/varint/-/varint-0.0.3.tgz#b821de9b04b38b3cd22f72c18d94a9fb72ab3518"
integrity sha1-uCHemwSzizzSL3LBjZSp+3KrNRg=
vary@^1, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"