Browse Source

Switch to tabs

pull/2/head
Ambrose Chua 3 years ago
parent
commit
82283461da
  1. 32
      .eslintrc.js
  2. 6
      babel.config.js
  3. 20
      package.json
  4. 6
      postcss.config.js
  5. 179
      src/api.js
  6. 32
      src/components/BlobSize.vue
  7. 6
      src/components/Error.vue
  8. 12
      src/components/Layout.vue
  9. 6
      src/components/ListItem.vue
  10. 6
      src/components/LoadableText.vue
  11. 22
      src/components/Paginator.vue
  12. 54
      src/components/TagSize.vue
  13. 4
      src/main.js
  14. 120
      src/options.js
  15. 58
      src/router.js
  16. 12
      src/views/Blob.vue
  17. 78
      src/views/Repo.vue
  18. 76
      src/views/Repos.vue
  19. 106
      src/views/Tag.vue
  20. 4
      vue.config.js
  21. 286
      yarn.lock

32
.eslintrc.js

@ -1,17 +1,19 @@
module.exports = {
root: true,
env: {
node: true,
},
extends: [
'plugin:vue/essential',
'@vue/airbnb',
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
},
parserOptions: {
parser: 'babel-eslint',
},
root: true,
env: {
node: true,
},
extends: [
'plugin:vue/essential',
'@vue/airbnb',
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
indent: ['error', 'tab'],
'no-tabs': 'off',
},
parserOptions: {
parser: 'babel-eslint',
},
};

6
babel.config.js

@ -1,5 +1,5 @@
module.exports = {
presets: [
'@vue/app',
],
presets: [
'@vue/app',
],
};

20
package.json

@ -1,7 +1,6 @@
{
"name": "dri",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
@ -19,6 +18,23 @@
"@vue/cli-plugin-eslint": "^3.0.3",
"@vue/cli-service": "^3.0.3",
"@vue/eslint-config-airbnb": "^3.0.3",
"vue-template-compiler": "^2.5.17"
"vue-template-compiler": "^2.5.17",
"lint-staged": "^6.0.0"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"Dockerfile": [
"hadolint"
],
"*.js": [
"vue-cli-service lint",
"git add"
],
"*.vue": [
"vue-cli-service lint",
"git add"
]
}
}

6
postcss.config.js

@ -1,5 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {},
},
plugins: {
autoprefixer: {},
},
};

179
src/api.js

@ -2,76 +2,163 @@ import parseLink from 'parse-link-header';
import { registryAPI, repositoriesPerPage, tagsPerPage, usePortusExplore } from '@/options';
function parseWWWAuthenticate(text) {
const result = {};
// extract auth-scheme
const schemeParts = text.split(' ');
[result.scheme] = schemeParts;
// extract auth-params
const remain = schemeParts.slice(1).join(' ');
const parts = remain.split(/ ?, ?/);
parts.forEach((part) => {
// parse auth-param
const kv = part.split('=');
if (kv.length === 2) {
const key = kv[0].trim();
const value = kv[1].trim();
if (value.startsWith('"') && value.endsWith('"')) {
result[key] = value.substring(1, value.length - 1);
} else {
result[key] = value;
}
} else {
result[parts] = true;
}
});
return result;
}
let cachedToken = null;
async function doAuth() {
if (cachedToken !== null) {
return cachedToken;
}
// try accessing registry API
const response = await fetch(`${await registryAPI()}/v2/`);
if (response.ok) {
// token not needed for registry
cachedToken = false;
return cachedToken;
}
if (response.status !== 401) {
throw new Error(response.statusText);
}
// solve authentication challenge
const { headers } = response;
if (!headers.has('Www-Authenticate')) {
throw new Error('no challenge presented');
}
const chal = parseWWWAuthenticate(headers.get('Www-Authenticate'));
if (chal.scheme !== 'Bearer') {
throw new Error('unsupported scheme');
}
const tokURL = new URL(chal.realm);
tokURL.searchParams.append('client_id', 'dri-client');
tokURL.searchParams.append('service', chal.service);
tokURL.searchParams.append('scope', 'repository:pwd/migrate:pull');
const tokResponse = await fetch(tokURL);
const tok = await tokResponse.json();
cachedToken = tok.token;
return tok.token;
}
async function paginatable(path, n, last = null) {
const url = new URL(`${await registryAPI()}${path}`);
if (n) url.searchParams.append('n', n);
if (last) url.searchParams.append('last', last);
const response = await fetch(url);
let nextLast = null;
if (response.headers.has('Link')) {
const links = parseLink(response.headers.get('Link'));
if (links && links.next) {
nextLast = links.next.last;
}
}
return Object.assign(await response.json(), { nextLast });
const token = await doAuth();
const url = new URL(`${await registryAPI()}${path}`);
if (n) url.searchParams.append('n', n);
if (last) url.searchParams.append('last', last);
const headers = {};
if (token) headers.Authorization = `Bearer ${token}`;
const response = await fetch(url, { headers });
let nextLast = null;
if (response.headers.has('Link')) {
const links = parseLink(response.headers.get('Link'));
if (links && links.next) {
nextLast = links.next.last;
}
}
return Object.assign(await response.json(), { nextLast });
}
async function get(path) {
const url = new URL(`${await registryAPI()}${path}`);
const response = await fetch(url);
return response.json();
const token = await doAuth();
const url = new URL(`${await registryAPI()}${path}`);
const headers = {};
if (token) headers.Authorization = `Bearer ${token}`;
const response = await fetch(url, { headers });
return response.json();
}
async function head(path) {
const url = new URL(`${await registryAPI()}${path}`);
const response = await fetch(url, { method: 'HEAD' });
return response.headers;
const token = await doAuth();
const url = new URL(`${await registryAPI()}${path}`);
const headers = {};
if (token) headers.Authorization = `Bearer ${token}`;
const response = await fetch(url, { method: 'HEAD', headers });
return response.headers;
}
async function portus() {
// TODO: Use the Portus API when it enables anonymous access
const response = await fetch(`${await registryAPI()}/explore?explore%5Bsearch%5D=`);
const html = await response.text();
// unconventionally parse out JSON from HTML
const startString = 'window.repositories = ';
const endString = ';</script>';
const string = html.substring(
html.lastIndexOf(startString) + startString.length,
html.indexOf(endString),
);
const object = JSON.parse(string);
return object;
}
async function repos(last = null) {
if (await usePortusExplore()) {
// TODO: Use the Portus API when it enables anonymous access
const response = await fetch(`${await registryAPI()}/explore?explore%5Bsearch%5D=`);
const html = await response.text();
// unconventionally parse out JSON from HTML
const startString = 'window.repositories = ';
const endString = ';</script>';
const string = html.substring(
html.lastIndexOf(startString) + startString.length,
html.indexOf(endString),
);
return JSON.parse(string);
}
return paginatable('/v2/_catalog', await repositoriesPerPage(), last);
if (await usePortusExplore()) {
const p = await portus();
return {
repositories: p.map(r => r.full_name),
};
}
return paginatable('/v2/_catalog', await repositoriesPerPage(), last);
}
async function repo(name) {
return get(`/v2/${name}`);
return get(`/v2/${name}`);
}
async function tags(name, last = null) {
return paginatable(`/v2/${name}/tags/list`, await tagsPerPage(), last);
if (await usePortusExplore()) {
const p = await portus();
return {
tags: p.find(r => r.full_name === name)
.tags.map(t => t[0].name),
};
}
return paginatable(`/v2/${name}/tags/list`, await tagsPerPage(), last);
}
async function tag(name, ref) {
return get(`/v2/${name}/manifests/${ref}`);
return get(`/v2/${name}/manifests/${ref}`);
}
async function blob(name, digest) {
const headers = await head(`/v2/${name}/blobs/${digest}`);
return {
contentLength: parseInt(headers.get('Content-Length'), 10),
};
const headers = await head(`/v2/${name}/blobs/${digest}`);
return {
contentLength: parseInt(headers.get('Content-Length'), 10),
};
}
export {
repos,
repo,
tags,
tag,
blob,
repos,
repo,
tags,
tag,
blob,
};

32
src/components/BlobSize.vue

@ -8,21 +8,21 @@ import { blob } from '@/api';
import LoadableText from '@/components/LoadableText.vue';
export default {
components: {
LoadableText,
},
props: {
repo: String,
blob: String,
},
data() {
return {
size: '',
};
},
async created() {
const size = await blob(this.repo, this.blob);
this.size = filesize(size.contentLength);
},
components: {
LoadableText,
},
props: {
repo: String,
blob: String,
},
data() {
return {
size: '',
};
},
async created() {
const size = await blob(this.repo, this.blob);
this.size = filesize(size.contentLength);
},
};
</script>

6
src/components/Error.vue

@ -4,9 +4,9 @@
<script>
export default {
props: {
message: String,
},
props: {
message: String,
},
};
</script>

12
src/components/Layout.vue

@ -24,12 +24,12 @@
import { version, source } from '@/options';
export default {
data() {
return {
version,
source,
};
},
data() {
return {
version,
source,
};
},
};
</script>

6
src/components/ListItem.vue

@ -10,9 +10,9 @@
<script>
export default {
props: {
to: { type: [Object, String], required: false },
},
props: {
to: { type: [Object, String], required: false },
},
};
</script>

6
src/components/LoadableText.vue

@ -4,9 +4,9 @@
<script>
export default {
props: {
text: String,
},
props: {
text: String,
},
};
</script>

22
src/components/Paginator.vue

@ -7,17 +7,17 @@
<script>
export default {
props: {
nextLast: String,
},
methods: {
prev() {
this.$router.back();
},
next() {
this.$router.push(`?last=${this.nextLast}`);
},
},
props: {
nextLast: String,
},
methods: {
prev() {
this.$router.back();
},
next() {
this.$router.push(`?last=${this.nextLast}`);
},
},
};
</script>

54
src/components/TagSize.vue

@ -8,32 +8,32 @@ import { tag, blob } from '@/api';
import LoadableText from '@/components/LoadableText.vue';
export default {
components: {
LoadableText,
},
props: {
repo: String,
tag: String,
},
data() {
return {
size: '',
};
},
async created() {
const r = await tag(this.repo, this.tag);
if (r.mediaType === 'application/vnd.docker.distribution.manifest.list.v2+json') {
console.error('V2 manifest lists not supported yet');
return;
}
if (r.schemaVersion === 1) {
r.layers = r.fsLayers.map(l => ({ digest: l.blobSum }));
}
const sizes = await Promise.all(r.layers.map(async layer => (
await blob(this.repo, layer.digest)
).contentLength));
const total = sizes.reduce((a, b) => a + b, 0);
this.size = filesize(total);
},
components: {
LoadableText,
},
props: {
repo: String,
tag: String,
},
data() {
return {
size: '',
};
},
async created() {
const r = await tag(this.repo, this.tag);
if (r.mediaType === 'application/vnd.docker.distribution.manifest.list.v2+json') {
console.error('V2 manifest lists not supported yet');
return;
}
if (r.schemaVersion === 1) {
r.layers = r.fsLayers.map(l => ({ digest: l.blobSum }));
}
const sizes = await Promise.all(r.layers.map(async layer => (
await blob(this.repo, layer.digest)
).contentLength));
const total = sizes.reduce((a, b) => a + b, 0);
this.size = filesize(total);
},
};
</script>

4
src/main.js

@ -7,6 +7,6 @@ import 'normalize.css';
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App),
router,
render: h => h(App),
}).$mount('#app');

120
src/options.js

@ -2,89 +2,89 @@ const version = process.env.VUE_APP_VERSION || '[master]';
const source = process.env.VUE_APP_SOURCE_LINK || 'https://github.com/productionwentdown/dri';
const defaultConfig = {
merged: false,
merged: false,
registryHost: process.env.VUE_APP_REGISTRY_HOST,
registryAPI: process.env.VUE_APP_REGISTRY_API,
registryHost: process.env.VUE_APP_REGISTRY_HOST,
registryAPI: process.env.VUE_APP_REGISTRY_API,
repositoriesPerPage: process.env.VUE_APP_REPOSITORIES_PER_PAGE,
tagsPerPage: process.env.VUE_APP_TAGS_PER_PAGE,
repositoriesPerPage: process.env.VUE_APP_REPOSITORIES_PER_PAGE,
tagsPerPage: process.env.VUE_APP_TAGS_PER_PAGE,
usePortusExplore: process.env.VUE_APP_USE_PORTUS_EXPLORE,
usePortusExplore: process.env.VUE_APP_USE_PORTUS_EXPLORE,
};
async function config() {
if (defaultConfig.merged) {
return defaultConfig;
}
if (defaultConfig.merged) {
return defaultConfig;
}
try {
const response = await fetch('config.json');
const jsonConfig = await response.json();
defaultConfig.merged = true;
return Object.assign(defaultConfig, jsonConfig);
} catch (_) {
defaultConfig.merged = true;
return defaultConfig;
}
try {
const response = await fetch('config.json');
const jsonConfig = await response.json();
defaultConfig.merged = true;
return Object.assign(defaultConfig, jsonConfig);
} catch (_) {
defaultConfig.merged = true;
return defaultConfig;
}
}
async function registryHost() {
const c = await config();
if (c.registryHost) {
return c.registryHost;
}
return window.location.host;
const c = await config();
if (c.registryHost) {
return c.registryHost;
}
return window.location.host;
}
async function registryAPI() {
const c = await config();
if (c.registryAPI) {
return c.registryAPI;
}
const host = await registryHost();
// assume API uses the same protocol as the page
// this is because browsers don't allow mixed content
// if a HTTPS API needs to be accessed over HTTP, configure registryAPI
return `${window.location.protocol}//${host}`;
const c = await config();
if (c.registryAPI) {
return c.registryAPI;
}
const host = await registryHost();
// assume API uses the same protocol as the page
// this is because browsers don't allow mixed content
// if a HTTPS API needs to be accessed over HTTP, configure registryAPI
return `${window.location.protocol}//${host}`;
}
async function usePortusExplore() {
const c = await config();
if (c.usePortusExplore) {
return true;
}
return false;
const c = await config();
if (c.usePortusExplore) {
return true;
}
return false;
}
async function repositoriesPerPage() {
const c = await config();
try {
const n = parseInt(c.repositoriesPerPage, 10);
if (n > 0) return n;
} catch (_) {
return 0;
}
return 0;
const c = await config();
try {
const n = parseInt(c.repositoriesPerPage, 10);
if (n > 0) return n;
} catch (_) {
return 0;
}
return 0;
}
async function tagsPerPage() {
const c = await config();
try {
const n = parseInt(c.tagsPerPage, 10);
if (n > 0) return n;
} catch (_) {
return 0;
}
return 0;
const c = await config();
try {
const n = parseInt(c.tagsPerPage, 10);
if (n > 0) return n;
} catch (_) {
return 0;
}
return 0;
}
export {
version,
source,
registryHost,
registryAPI,
repositoriesPerPage,
tagsPerPage,
usePortusExplore,
version,
source,
registryHost,
registryAPI,
repositoriesPerPage,
tagsPerPage,
usePortusExplore,
};

58
src/router.js

@ -8,28 +8,40 @@ import Blob from '@/views/Blob.vue';
Vue.use(Router);
const removeEncode = (to, _, next) => {
if (to.path.indexOf('%2F') > -1) {
return next({
path: to.path.replace('%2F', '/'),
});
}
return next();
};
export default new Router({
//mode: 'history',
routes: [
{
path: '/',
name: 'repos',
component: Repos,
},
{
path: '/:repo+/blobs/:digest',
name: 'blob',
component: Blob,
},
{
path: '/:repo+/tags/:tag',
name: 'tag',
component: Tag,
},
{
path: '/:repo+',
name: 'repo',
component: Repo,
},
],
// mode: 'history',
routes: [
{
path: '/',
name: 'repos',
component: Repos,
},
{
path: '/:repo+/blobs/:digest',
name: 'blob',
component: Blob,
beforeEnter: removeEncode,
},
{
path: '/:repo+/tags/:tag',
name: 'tag',
component: Tag,
beforeEnter: removeEncode,
},
{
path: '/:repo+',
name: 'repo',
component: Repo,
beforeEnter: removeEncode,
},
],
});

12
src/views/Blob.vue

@ -22,11 +22,11 @@ import ListItem from '@/components/ListItem.vue';
import BlobSize from '@/components/BlobSize.vue';
export default {
components: {
Layout,
List,
ListItem,
BlobSize,
},
components: {
Layout,
List,
ListItem,
BlobSize,
},
};
</script>

78
src/views/Repo.vue

@ -39,44 +39,44 @@ import Paginator from '@/components/Paginator.vue';
import TagSize from '@/components/TagSize.vue';
export default {
components: {
Layout,
Error,
Toolbar,
List,
ListHeader,
ListItem,
Paginator,
TagSize,
},
data() {
return {
error: '',
registryHost: '',
tags: [],
nextLast: '',
};
},
async created() {
this.registryHost = await registryHost();
await this.fetchTags();
},
methods: {
async fetchTags() {
try {
const r = await tags(this.$route.params.repo, this.$route.query.last);
this.tags = r.tags;
this.nextLast = r.nextLast;
} catch (e) {
console.error(e);
this.error = `Unable to fetch tags (${e.name})`;
}
},
},
watch: {
async $route() {
await this.fetchTags();
},
},
components: {
Layout,
Error,
Toolbar,
List,
ListHeader,
ListItem,
Paginator,
TagSize,
},
data() {
return {
error: '',
registryHost: '',
tags: [],
nextLast: '',
};
},
async created() {
this.registryHost = await registryHost();
await this.fetchTags();
},
methods: {
async fetchTags() {
try {
const r = await tags(this.$route.params.repo, this.$route.query.last);
this.tags = r.tags;
this.nextLast = r.nextLast;
} catch (e) {
console.error(e);
this.error = `Unable to fetch tags (${e.name})`;
}
},
},
watch: {
async $route() {
await this.fetchTags();
},
},
};
</script>

76
src/views/Repos.vue

@ -36,43 +36,43 @@ import ListItem from '@/components/ListItem.vue';
import Paginator from '@/components/Paginator.vue';
export default {
components: {
Layout,
Error,
Toolbar,
List,
ListHeader,
ListItem,
Paginator,
},
data() {
return {
error: '',
registryHost: '',
repos: [],
nextLast: '',
};
},
async created() {
this.registryHost = await registryHost();
await this.fetchRepos();
},
methods: {
async fetchRepos() {
try {
const r = await repos(this.$route.query.last);
this.repos = r.repositories;
this.nextLast = r.nextLast;
} catch (e) {
console.error(e);
this.error = `Unable to fetch repositories (${e.name})`;
}
},
},
watch: {
async $route() {
await this.fetchRepos();
},
},
components: {
Layout,
Error,
Toolbar,
List,
ListHeader,
ListItem,
Paginator,
},
data() {
return {
error: '',
registryHost: '',
repos: [],
nextLast: '',
};
},
async created() {
this.registryHost = await registryHost();
await this.fetchRepos();
},
methods: {
async fetchRepos() {
try {
const r = await repos(this.$route.query.last);
this.repos = r.repositories;
this.nextLast = r.nextLast;
} catch (e) {
console.error(e);
this.error = `Unable to fetch repositories (${e.name})`;
}
},
},
watch: {
async $route() {
await this.fetchRepos();
},
},
};
</script>

106
src/views/Tag.vue

@ -14,7 +14,9 @@
</ListItem>
<ListItem>
<span slot="title">Size</span>
<span slot="detail"><TagSize :repo="$route.params.repo" :tag="$route.params.tag" /></span>
<span slot="detail">
<TagSize :repo="$route.params.repo" :tag="$route.params.tag" />
</span>
</ListItem>
</List>
<h2>Layers</h2>
@ -50,56 +52,56 @@ import TagSize from '@/components/TagSize.vue';
import BlobSize from '@/components/BlobSize.vue';
export default {
components: {
Layout,
Error,
Toolbar,
List,
ListHeader,
ListItem,
TagSize,
BlobSize,
},
data() {
return {
error: '',
registryHost: '',
tag: {},
layers: [],
};
},
async created() {
this.registryHost = await registryHost();
await this.fetchTag();
},
methods: {
async fetchTag() {
try {
const r = await tag(this.$route.params.repo, this.$route.params.tag);
if (r.mediaType === 'application/vnd.docker.distribution.manifest.list.v2+json') {
this.error = 'V2 manifest lists not supported yet';
}
if (r.schemaVersion === 1) {
r.layers = r.fsLayers.map(l => ({ digest: l.blobSum }));
}
this.tag = r;
console.log(r);
} catch (e) {
console.error(e);
this.error = `Unable to fetch tag (${e.name})`;
}
},
identifier(t, n) {
return t.layers[n].digest.split(':')[1].slice(0, 10);
},
command() {
return 'not implemented';
},
},
watch: {
async $route() {
await this.fetchTag();
},
},
components: {
Layout,
Error,
Toolbar,
List,
ListHeader,
ListItem,
TagSize,
BlobSize,
},
data() {
return {
error: '',
registryHost: '',
tag: {},
layers: [],
};
},
async created() {
this.registryHost = await registryHost();
await this.fetchTag();
},
methods: {
async fetchTag() {
try {
const r = await tag(this.$route.params.repo, this.$route.params.tag);
if (r.mediaType === 'application/vnd.docker.distribution.manifest.list.v2+json') {
this.error = 'V2 manifest lists not supported yet';
}
if (r.schemaVersion === 1) {
r.layers = r.fsLayers.map(l => ({ digest: l.blobSum }));
}
this.tag = r;
console.log(r);
} catch (e) {
console.error(e);
this.error = `Unable to fetch tag (${e.name})`;
}
},
identifier(t, n) {
return t.layers[n].digest.split(':')[1].slice(0, 10);
},
command() {
return 'not implemented';
},
},
watch: {
async $route() {
await this.fetchTag();
},
},
};
</script>

4
vue.config.js

@ -1,4 +1,4 @@
module.exports = {
lintOnSave: false,
baseUrl: '',
lintOnSave: false,
baseUrl: '',
};

286
yarn.lock

@ -1001,6 +1001,10 @@ ansi-colors@^3.0.0:
version "3.0.6"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.0.6.tgz#a0b9e00e8c1cc6685b1c3130dbeb9abed03ca6a4"
ansi-escapes@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
ansi-escapes@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
@ -1021,12 +1025,16 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
ansi-styles@^3.2.1:
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
any-observable@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242"
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@ -1034,6 +1042,10 @@ anymatch@^2.0.0:
micromatch "^3.1.4"
normalize-path "^2.1.1"
app-root-path@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a"
aproba@^1.0.3, aproba@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@ -1554,7 +1566,7 @@ caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
chalk@^1.1.3:
chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
@ -1639,16 +1651,33 @@ clean-css@4.2.x:
dependencies:
source-map "~0.6.0"
cli-cursor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
dependencies:
restore-cursor "^1.0.1"
cli-cursor@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
dependencies:
restore-cursor "^2.0.0"
cli-spinners@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c"
cli-spinners@^1.1.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a"
cli-truncate@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
dependencies:
slice-ansi "0.0.4"
string-width "^1.0.1"
cli-width@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
@ -1741,7 +1770,7 @@ commander@2.17.x, commander@~2.17.1:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
commander@^2.13.0:
commander@^2.11.0, commander@^2.13.0, commander@^2.9.0:
version "2.18.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970"
@ -2119,6 +2148,10 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
date-fns@^1.27.2:
version "1.29.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
@ -2155,6 +2188,10 @@ decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
dedent@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
deep-equal@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@ -2405,6 +2442,10 @@ electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.62:
version "1.3.70"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.70.tgz#ded377256d92d81b4257d36c65aa890274afcfd2"
elegant-spinner@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
elliptic@^6.0.0:
version "6.4.1"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a"
@ -2718,6 +2759,10 @@ execa@^0.8.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
exit-hook@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
@ -2876,6 +2921,13 @@ figgy-pudding@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
figures@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
dependencies:
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
figures@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
@ -2951,6 +3003,10 @@ find-cache-dir@^1.0.0:
make-dir "^1.0.0"
pkg-dir "^2.0.0"
find-parent-dir@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
@ -3110,6 +3166,10 @@ get-caller-file@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
get-own-enumerable-property-symbols@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b"
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@ -3504,6 +3564,16 @@ imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
indent-string@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
dependencies:
repeating "^2.0.0"
indent-string@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@ -3719,6 +3789,12 @@ is-extglob@^2.1.0, is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
is-finite@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
dependencies:
number-is-nan "^1.0.0"
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
@ -3763,10 +3839,16 @@ is-number@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
is-obj@^1.0.0:
is-obj@^1.0.0, is-obj@^1.0.1:
version "1.0.1"
resolved "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
is-observable@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2"
dependencies:
symbol-observable "^0.2.2"
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@ -3807,6 +3889,10 @@ is-regex@^1.0.4:
dependencies:
has "^1.0.1"
is-regexp@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
is-relative@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5"
@ -3891,6 +3977,19 @@ javascript-stringify@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3"
jest-get-type@^21.2.0:
version "21.2.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23"
jest-validate@^21.1.0:
version "21.2.1"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7"
dependencies:
chalk "^2.0.1"
jest-get-type "^21.2.0"
leven "^2.1.0"
pretty-format "^21.2.1"
joi@^13.0.0:
version "13.6.0"
resolved "https://registry.yarnpkg.com/joi/-/joi-13.6.0.tgz#877d820e3ad688a49c32421ffefc746bfbe2d0a0"
@ -4030,6 +4129,10 @@ lcid@^2.0.0:
dependencies:
invert-kv "^2.0.0"
leven@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
@ -4037,6 +4140,79 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
lint-staged@^6.0.0:
version "6.1.1"
resolved "http://registry.npmjs.org/lint-staged/-/lint-staged-6.1.1.tgz#cd08c4d9b8ccc2d37198d1c47ce77d22be6cf324"
dependencies:
app-root-path "^2.0.0"
chalk "^2.1.0"
commander "^2.11.0"
cosmiconfig "^4.0.0"
debug "^3.1.0"
dedent "^0.7.0"
execa "^0.8.0"
find-parent-dir "^0.3.0"
is-glob "^4.0.0"
jest-validate "^21.1.0"
listr "^0.13.0"
lodash "^4.17.4"
log-symbols "^2.0.0"
minimatch "^3.0.0"
npm-which "^3.0.1"
p-map "^1.1.1"
path-is-inside "^1.0.2"
pify "^3.0.0"
staged-git-files "1.0.0"
stringify-object "^3.2.0"
listr-silent-renderer@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e"
listr-update-renderer@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7"
dependencies:
chalk "^1.1.3"
cli-truncate "^0.2.1"
elegant-spinner "^1.0.1"
figures "^1.7.0"
indent-string "^3.0.0"
log-symbols "^1.0.2"
log-update "^1.0.2"
strip-ansi "^3.0.1"
listr-verbose-renderer@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35"
dependencies:
chalk "^1.1.3"
cli-cursor "^1.0.2"
date-fns "^1.27.2"
figures "^1.7.0"
listr@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d"
dependencies:
chalk "^1.1.3"
cli-truncate "^0.2.1"
figures "^1.7.0"
indent-string "^2.1.0"
is-observable "^0.2.0"
is-promise "^2.1.0"
is-stream "^1.1.0"
listr-silent-renderer "^1.1.1"
listr-update-renderer "^0.4.0"
listr-verbose-renderer "^0.4.0"
log-symbols "^1.0.2"
log-update "^1.0.2"
ora "^0.2.3"
p-map "^1.1.1"
rxjs "^5.4.2"
stream-to-observable "^0.2.0"
strip-ansi "^3.0.1"
load-json-file@^2.0.0:
version "2.0.0"
resolved "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
@ -4124,12 +4300,25 @@ lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5,
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
log-symbols@^2.2.0:
log-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
dependencies:
chalk "^1.0.0"
log-symbols@^2.0.0, log-symbols@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
dependencies:
chalk "^2.0.1"
log-update@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1"
dependencies:
ansi-escapes "^1.0.0"
cli-cursor "^1.0.2"
loglevel@^1.4.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
@ -4314,7 +4503,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
@ -4563,12 +4752,26 @@ npm-packlist@^1.1.6:
ignore-walk "^3.0.1"
npm-bundled "^1.0.1"
npm-path@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64"
dependencies:
which "^1.2.10"
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
dependencies:
path-key "^2.0.0"
npm-which@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
dependencies:
commander "^2.9.0"
npm-path "^2.0.2"
which "^1.2.10"
npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@ -4680,6 +4883,10 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies:
wrappy "1"
onetime@^1.0.0:
version "1.1.0"
resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
onetime@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
@ -4707,6 +4914,15 @@ optionator@^0.8.2:
type-check "~0.3.2"
wordwrap "~1.0.0"
ora@^0.2.3:
version "0.2.3"
resolved "http://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4"
dependencies:
chalk "^1.1.1"
cli-cursor "^1.0.2"
cli-spinners "^0.1.2"
object-assign "^4.0.1"
ora@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b"
@ -5298,6 +5514,13 @@ pretty-error@^2.0.2:
renderkid "^2.0.1"
utila "~0.4"
pretty-format@^21.2.1:
version "21.2.1"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-21.2.1.tgz#ae5407f3cf21066cd011aa1ba5fce7b6a2eddb36"
dependencies:
ansi-regex "^3.0.0"
ansi-styles "^3.2.0"
private@^0.1.6:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@ -5602,6 +5825,12 @@ repeat-string@^1.5.2, repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
repeating@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
dependencies:
is-finite "^1.0.0"
request-promise-core@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6"
@ -5688,6 +5917,13 @@ resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0:
dependencies:
path-parse "^1.0.5"
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
dependencies:
exit-hook "^1.0.0"
onetime "^1.0.0"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@ -5742,6 +5978,12 @@ rx-lite@*, rx-lite@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
rxjs@^5.4.2:
version "5.5.12"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc"
dependencies:
symbol-observable "1.0.1"
safe-buffer@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
@ -5914,6 +6156,10 @@ slash@^2.0.0:
version "2.0.0"