Update vue-resource

This commit is contained in:
Filipa Lacerda 2017-07-12 14:47:09 +00:00 committed by Phil Hughes
parent fd692d1066
commit aaa78199c2
28 changed files with 328 additions and 171 deletions

View file

@ -51,8 +51,9 @@ export default () => {
methods: {
loadFile() {
this.$http.get(el.dataset.endpoint)
.then(response => response.json())
.then((res) => {
this.json = res.json();
this.json = res;
this.loading = false;
})
.catch((e) => {

View file

@ -81,8 +81,9 @@ $(() => {
mounted () {
Store.disabled = this.disabled;
gl.boardService.all()
.then(response => response.json())
.then((resp) => {
resp.json().forEach((board) => {
resp.forEach((board) => {
const list = Store.addList(board, this.defaultAvatar);
if (list.type === 'closed') {
@ -97,7 +98,8 @@ $(() => {
Store.addBlankState();
this.loading = false;
}).catch(() => new Flash('An error occurred. Please try again.'));
})
.catch(() => new Flash('An error occurred. Please try again.'));
},
methods: {
updateTokens() {

View file

@ -64,8 +64,9 @@ export default {
// Save the labels
gl.boardService.generateDefaultLists()
.then((resp) => {
resp.json().forEach((listObj) => {
.then(resp => resp.json())
.then((data) => {
data.forEach((listObj) => {
const list = Store.findList('title', listObj.title);
list.id = listObj.id;

View file

@ -88,9 +88,9 @@ gl.issueBoards.IssuesModal = Vue.extend({
return gl.boardService.getBacklog(queryData(this.filter.path, {
page: this.page,
per: this.perPage,
})).then((res) => {
const data = res.json();
}))
.then(resp => resp.json())
.then((data) => {
if (clearIssues) {
this.issues = [];
}

View file

@ -40,9 +40,8 @@ class List {
save () {
return gl.boardService.createList(this.label.id)
.then((resp) => {
const data = resp.json();
.then(resp => resp.json())
.then((data) => {
this.id = data.id;
this.type = data.list_type;
this.position = data.position;
@ -91,8 +90,8 @@ class List {
}
return gl.boardService.getIssuesForList(this.id, data)
.then((resp) => {
const data = resp.json();
.then(resp => resp.json())
.then((data) => {
this.loading = false;
this.issuesSize = data.size;
@ -109,8 +108,8 @@ class List {
this.issuesSize += 1;
return gl.boardService.newIssue(this.id, issue)
.then((resp) => {
const data = resp.json();
.then(resp => resp.json())
.then((data) => {
issue.id = data.iid;
if (this.issuesSize > 1) {

View file

@ -23,11 +23,6 @@ class BoardService {
url: bulkUpdatePath,
},
});
Vue.http.interceptors.push((request, next) => {
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
next();
});
}
all () {

View file

@ -51,11 +51,11 @@
},
methods: {
successCallback(resp) {
const response = resp.json();
// depending of the endpoint the response can either bring a `pipelines` key or not.
const pipelines = response.pipelines || response;
this.setCommonData(pipelines);
return resp.json().then((response) => {
// depending of the endpoint the response can either bring a `pipelines` key or not.
const pipelines = response.pipelines || response;
this.setCommonData(pipelines);
});
},
},
};

View file

@ -1,4 +1,4 @@
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, max-len */
/* global CommentsStore */
/* global ResolveService */
/* global Flash */
@ -64,8 +64,6 @@ const ResolveBtn = Vue.extend({
});
},
resolve: function () {
const errorFlashMsg = 'An error occurred when trying to resolve a comment. Please try again.';
if (!this.canResolve) return;
let promise;
@ -79,24 +77,20 @@ const ResolveBtn = Vue.extend({
.resolve(this.noteId);
}
promise.then((response) => {
this.loading = false;
promise
.then(resp => resp.json())
.then((data) => {
this.loading = false;
if (response.status === 200) {
const data = response.json();
const resolved_by = data ? data.resolved_by : null;
CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolved_by);
this.discussion.updateHeadline(data);
gl.mrWidget.checkStatus();
} else {
new Flash(errorFlashMsg);
}
this.updateTooltip();
}).catch(() => {
new Flash(errorFlashMsg);
});
this.updateTooltip();
})
.catch(() => new Flash('An error occurred when trying to resolve a comment. Please try again.'));
}
},
mounted: function () {

View file

@ -1,4 +1,3 @@
/* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */
/* global Flash */
/* global CommentsStore */
@ -32,27 +31,22 @@ class ResolveServiceClass {
promise = this.resolveAll(mergeRequestId, discussionId);
}
promise.then((response) => {
discussion.loading = false;
if (response.status === 200) {
const data = response.json();
const resolved_by = data ? data.resolved_by : null;
promise
.then(resp => resp.json())
.then((data) => {
discussion.loading = false;
const resolvedBy = data ? data.resolved_by : null;
if (isResolved) {
discussion.unResolveAllNotes();
} else {
discussion.resolveAllNotes(resolved_by);
discussion.resolveAllNotes(resolvedBy);
}
gl.mrWidget.checkStatus();
discussion.updateHeadline(data);
} else {
throw new Error('An error occurred when trying to resolve discussion.');
}
}).catch(() => {
new Flash('An error occurred when trying to resolve a discussion. Please try again.');
});
})
.catch(() => new Flash('An error occurred when trying to resolve a discussion. Please try again.'));
}
resolveAll(mergeRequestId, discussionId) {
@ -62,7 +56,7 @@ class ResolveServiceClass {
return this.discussionResource.save({
mergeRequestId,
discussionId
discussionId,
}, {});
}
@ -73,7 +67,7 @@ class ResolveServiceClass {
return this.discussionResource.delete({
mergeRequestId,
discussionId
discussionId,
}, {});
}
}

View file

@ -1,17 +1,15 @@
export default {
methods: {
saveData(resp) {
const response = {
headers: resp.headers,
body: resp.json(),
};
const headers = resp.headers;
return resp.json().then((response) => {
this.isLoading = false;
this.isLoading = false;
this.store.storeAvailableCount(response.body.available_count);
this.store.storeStoppedCount(response.body.stopped_count);
this.store.storeEnvironments(response.body.environments);
this.store.setPagination(response.headers);
this.store.storeAvailableCount(response.available_count);
this.store.storeStoppedCount(response.stopped_count);
this.store.storeEnvironments(response.environments);
this.store.setPagination(headers);
});
},
},
};

View file

@ -99,8 +99,10 @@ document.addEventListener('DOMContentLoaded', () => {
page: currentPath,
}, document.title, currentPath);
this.updateGroups(response.json());
this.updatePagination(response.headers);
return response.json().then((data) => {
this.updateGroups(data);
this.updatePagination(response.headers);
});
})
.catch(this.handleErrorResponse);
},
@ -114,18 +116,19 @@ document.addEventListener('DOMContentLoaded', () => {
},
leaveGroup(group, collection) {
this.service.leaveGroup(group.leavePath)
.then(resp => resp.json())
.then((response) => {
$.scrollTo(0);
this.store.removeGroup(group, collection);
// eslint-disable-next-line no-new
new Flash(response.json().notice, 'notice');
new Flash(response.notice, 'notice');
})
.catch((response) => {
.catch((error) => {
let message = 'An error occurred. Please try again.';
if (response.status === 403) {
if (error.status === 403) {
message = 'Failed to leave the group. Please make sure you are not the only owner';
}

View file

@ -202,10 +202,7 @@ export default {
this.poll = new Poll({
resource: this.service,
method: 'getData',
successCallback: (res) => {
const data = res.json();
this.store.updateState(data);
},
successCallback: res => res.json().then(data => this.store.updateState(data)),
errorCallback(err) {
throw new Error(err);
},

View file

@ -54,9 +54,8 @@ export default class JobMediator {
}
successCallback(response) {
const data = response.json();
this.state.isLoading = false;
this.store.storeJob(data);
return response.json().then(data => this.store.storeJob(data));
}
errorCallback() {

View file

@ -1270,7 +1270,7 @@ export default class Notes {
<div class="timeline-entry-inner">
<div class="timeline-icon">
<a href="/${currentUsername}">
<img class="avatar s40" src="${currentUserAvatar}">
<img class="avatar s40" src="${currentUserAvatar}" />
</a>
</div>
<div class="timeline-content ${discussionClass}">

View file

@ -129,14 +129,11 @@
},
successCallback(resp) {
const response = {
headers: resp.headers,
body: resp.json(),
};
this.store.storeCount(response.body.count);
this.store.storePagination(response.headers);
this.setCommonData(response.body.pipelines);
return resp.json().then((response) => {
this.store.storeCount(response.count);
this.store.storePagination(resp.headers);
this.setCommonData(response.pipelines);
});
},
},
};

View file

@ -73,8 +73,9 @@ export default {
fetchJobs() {
this.$http.get(this.stage.dropdown_path)
.then((response) => {
this.dropdownContent = response.json().html;
.then(response => response.json())
.then((data) => {
this.dropdownContent = data.html;
this.isLoading = false;
})
.catch(() => {

View file

@ -40,10 +40,10 @@ export default class pipelinesMediator {
}
successCallback(response) {
const data = response.json();
this.state.isLoading = false;
this.store.storePipeline(data);
return response.json().then((data) => {
this.state.isLoading = false;
this.store.storePipeline(data);
});
}
errorCallback() {

View file

@ -28,8 +28,8 @@ export default class SidebarMediator {
fetch() {
this.service.get()
.then((response) => {
const data = response.json();
.then(response => response.json())
.then((data) => {
this.store.setAssigneeData(data);
this.store.setTimeTrackingData(data);
})

View file

@ -44,9 +44,8 @@
text: this.$slots.textarea[0].elm.value,
},
)
.then((res) => {
const data = res.json();
.then(resp => resp.json())
.then((data) => {
this.markdownPreviewLoading = false;
this.markdownPreview = data.body;

View file

@ -14,11 +14,22 @@ Vue.http.interceptors.push((request, next) => {
});
});
// Inject CSRF token so we don't break any tests.
// Inject CSRF token and parse headers.
// New Vue Resource version uses Headers, we are expecting a plain object to render pagination
// and polling.
Vue.http.interceptors.push((request, next) => {
if ($.rails) {
// eslint-disable-next-line no-param-reassign
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
request.headers.set('X-CSRF-Token', $.rails.csrfToken());
}
next();
next((response) => {
// Headers object has a `forEach` property that iterates through all values.
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
// eslint-disable-next-line no-param-reassign
response.headers = headers;
});
});

View file

@ -0,0 +1,4 @@
---
title: Updates vue resource and code according to breaking changes
merge_request:
author:

View file

@ -112,7 +112,50 @@ Vue Resource should only be imported in the service file.
Vue.use(VueResource);
```
### CSRF token
#### Vue-resource gotchas
#### Headers
Headers are being parsed into a plain object in an interceptor.
In Vue-resource 1.x `headers` object was changed into an `Headers` object. In order to not change all old code, an interceptor was added.
If you need to write a unit test that takes the headers in consideration, you need to include an interceptor to parse the headers after your test interceptor.
You can see an example in `spec/javascripts/environments/environment_spec.js`:
```javascript
import { headersInterceptor } from './helpers/vue_resource_helper';
beforeEach(() => {
Vue.http.interceptors.push(myInterceptor);
Vue.http.interceptors.push(headersInterceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, myInterceptor);
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
```
#### `.json()`
When making a request to the server, you will most likely need to access the body of the response.
Use `.json()` to convert. Because `.json()` returns a Promise the follwoing structure should be used:
```javascript
service.get('url')
.then(resp => resp.json())
.then((data) => {
this.store.storeData(data);
})
.catch(() => new Flash('Something went wrong'));
```
When using `Poll` (`app/assets/javascripts/lib/utils/poll.js`), the `successCallback` needs to handle `.json()` as a Promise:
```javascript
successCallback: (response) => {
return response.json().then((data) => {
// handle the response
});
}
```
#### CSRF token
We use a Vue Resource interceptor to manage the CSRF token.
`app/assets/javascripts/vue_shared/vue_resource_interceptor.js` holds all our common interceptors.
Note: You don't need to load `app/assets/javascripts/vue_shared/vue_resource_interceptor.js`
@ -126,13 +169,13 @@ The following example shows an application:
// store.js
export default class Store {
/**
/**
* This is where we will iniatialize the state of our data.
* Usually in a small SPA you don't need any options when starting the store. In the case you do
* need guarantee it's an Object and it's documented.
*
* @param {Object} options
*/
*
* @param {Object} options
*/
constructor(options) {
this.options = options;
@ -205,14 +248,14 @@ import Store from 'store';
import Service from 'service';
import TodoComponent from 'todoComponent';
export default {
/**
/**
* Although most data belongs in the store, each component it's own state.
* We want to show a loading spinner while we are fetching the todos, this state belong
* in the component.
*
* We need to access the store methods through all methods of our component.
* We need to access the state of our store.
*/
*/
data() {
const store = new Store();
@ -396,42 +439,46 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e
[Vue Resource Interceptors][vue-resource-interceptor] allow us to add a interceptor with
the response we need:
```javascript
// Mock the service to return data
const interceptor = (request, next) => {
next(request.respondWith(JSON.stringify([{
title: 'This is a todo',
body: 'This is the text'
}]), {
status: 200,
}));
};
```javascript
// Mock the service to return data
const interceptor = (request, next) => {
next(request.respondWith(JSON.stringify([{
title: 'This is a todo',
body: 'This is the text'
}]), {
status: 200,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
});
it('should do something', (done) => {
setTimeout(() => {
// Test received data
done();
}, 0);
});
```
it('should do something', (done) => {
setTimeout(() => {
// Test received data
done();
}, 0);
});
```
1. Headers interceptor
Refer to [this section](vue.md#headers)
1. Use `$.mount()` to mount the component
```javascript
// bad
new Component({
el: document.createElement('div')
});
// good
new Component().$mount();
```javascript
// bad
new Component({
el: document.createElement('div')
});
// good
new Component().$mount();
```
[vue-docs]: http://vuejs.org/guide/index.html

View file

@ -58,7 +58,7 @@
"visibilityjs": "^1.2.4",
"vue": "^2.2.6",
"vue-loader": "^11.3.4",
"vue-resource": "^0.9.3",
"vue-resource": "^1.3.4",
"vue-template-compiler": "^2.2.6",
"webpack": "^2.6.1",
"webpack-bundle-analyzer": "^2.8.2"

View file

@ -2,6 +2,7 @@ import Vue from 'vue';
import '~/flash';
import environmentsComponent from '~/environments/components/environment.vue';
import { environment, folder } from './mock_data';
import { headersInterceptor } from '../helpers/vue_resource_helper';
describe('Environment', () => {
preloadFixtures('static/environments/environments.html.raw');
@ -25,12 +26,14 @@ describe('Environment', () => {
beforeEach(() => {
Vue.http.interceptors.push(environmentsEmptyResponseInterceptor);
Vue.http.interceptors.push(headersInterceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsEmptyResponseInterceptor,
);
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
it('should render the empty state', (done) => {
@ -54,6 +57,10 @@ describe('Environment', () => {
describe('with paginated environments', () => {
const environmentsResponseInterceptor = (request, next) => {
next((response) => {
response.headers.set('X-nExt-pAge', '2');
});
next(request.respondWith(JSON.stringify({
environments: [environment],
stopped_count: 1,
@ -73,6 +80,7 @@ describe('Environment', () => {
beforeEach(() => {
Vue.http.interceptors.push(environmentsResponseInterceptor);
Vue.http.interceptors.push(headersInterceptor);
component = new EnvironmentsComponent({
el: document.querySelector('#environments-list-view'),
});
@ -82,6 +90,7 @@ describe('Environment', () => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsResponseInterceptor,
);
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
it('should render a table with environments', (done) => {

View file

@ -2,6 +2,7 @@ import Vue from 'vue';
import '~/flash';
import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
import { environmentsList } from '../mock_data';
import { headersInterceptor } from '../../helpers/vue_resource_helper';
describe('Environments Folder View', () => {
preloadFixtures('static/environments/environments_folder_view.html.raw');
@ -36,6 +37,8 @@ describe('Environments Folder View', () => {
beforeEach(() => {
Vue.http.interceptors.push(environmentsResponseInterceptor);
Vue.http.interceptors.push(headersInterceptor);
component = new EnvironmentsFolderViewComponent({
el: document.querySelector('#environments-folder-list-view'),
});
@ -45,6 +48,7 @@ describe('Environments Folder View', () => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsResponseInterceptor,
);
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
it('should render a table with environments', (done) => {

View file

@ -0,0 +1,11 @@
// eslint-disable-next-line import/prefer-default-export
export const headersInterceptor = (request, next) => {
next((response) => {
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
// eslint-disable-next-line no-param-reassign
response.headers = headers;
});
};

View file

@ -3,7 +3,6 @@ import '~/render_math';
import '~/render_gfm';
import issuableApp from '~/issue_show/components/app.vue';
import eventHub from '~/issue_show/event_hub';
import Poll from '~/lib/utils/poll';
import issueShowData from '../mock_data';
function formatText(text) {
@ -11,16 +10,26 @@ function formatText(text) {
}
describe('Issuable output', () => {
let requestData = issueShowData.initialRequest;
document.body.innerHTML = '<span id="task_status"></span>';
const interceptor = (request, next) => {
next(request.respondWith(JSON.stringify(requestData), {
status: 200,
}));
};
let vm;
beforeEach(() => {
beforeEach((done) => {
spyOn(eventHub, '$emit');
spyOn(Poll.prototype, 'makeRequest');
const IssuableDescriptionComponent = Vue.extend(issuableApp);
requestData = issueShowData.initialRequest;
Vue.http.interceptors.push(interceptor);
vm = new IssuableDescriptionComponent({
propsData: {
canUpdate: true,
@ -40,15 +49,17 @@ describe('Issuable output', () => {
projectPath: '/',
},
}).$mount();
setTimeout(done);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
vm.poll.stop();
});
it('should render a title/description/edited and update title/description/edited on update', (done) => {
vm.poll.options.successCallback({
json() {
return issueShowData.initialRequest;
},
});
let editedText;
Vue.nextTick()
.then(() => {
@ -64,13 +75,10 @@ describe('Issuable output', () => {
expect(editedText.querySelector('time')).toBeTruthy();
})
.then(() => {
vm.poll.options.successCallback({
json() {
return issueShowData.secondRequest;
},
});
requestData = issueShowData.secondRequest;
vm.poll.makeRequest();
})
.then(Vue.nextTick)
.then(() => new Promise(resolve => setTimeout(resolve)))
.then(() => {
expect(document.querySelector('title').innerText).toContain('2 (#1)');
expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>2</p>');
@ -304,7 +312,7 @@ describe('Issuable output', () => {
it('stops polling when deleting', (done) => {
spyOn(gl.utils, 'visitUrl');
spyOn(vm.poll, 'stop');
spyOn(vm.poll, 'stop').and.callThrough();
spyOn(vm.service, 'deleteIssuable').and.callFake(() => new Promise((resolve) => {
resolve({
json() {
@ -347,23 +355,14 @@ describe('Issuable output', () => {
describe('open form', () => {
it('shows locked warning if form is open & data is different', (done) => {
vm.poll.options.successCallback({
json() {
return issueShowData.initialRequest;
},
});
Vue.nextTick()
.then(() => {
vm.openForm();
vm.poll.options.successCallback({
json() {
return issueShowData.secondRequest;
},
});
requestData = issueShowData.secondRequest;
vm.poll.makeRequest();
})
.then(Vue.nextTick)
.then(() => new Promise(resolve => setTimeout(resolve)))
.then(() => {
expect(
vm.formState.lockedWarningVisible,

102
yarn.lock
View file

@ -1575,6 +1575,12 @@ deckar01-task_list@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/deckar01-task_list/-/deckar01-task_list-2.0.0.tgz#7f7a595430d21b3036ed5dfbf97d6b65de18e2c9"
decompress-response@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
dependencies:
mimic-response "^1.0.0"
deep-extend@~0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
@ -1712,6 +1718,10 @@ dropzone@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-4.2.0.tgz#fbe7acbb9918e0706489072ef663effeef8a79f3"
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:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
@ -2445,6 +2455,10 @@ get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
getpass@^0.1.1:
version "0.1.6"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
@ -2521,6 +2535,25 @@ got@^3.2.0:
read-all-stream "^3.0.0"
timed-out "^2.0.0"
got@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
dependencies:
decompress-response "^3.2.0"
duplexer3 "^0.1.4"
get-stream "^3.0.0"
is-plain-obj "^1.1.0"
is-retry-allowed "^1.0.0"
is-stream "^1.0.0"
isurl "^1.0.0-alpha5"
lowercase-keys "^1.0.0"
p-cancelable "^0.3.0"
p-timeout "^1.1.1"
safe-buffer "^5.0.1"
timed-out "^4.0.0"
url-parse-lax "^1.0.0"
url-to-options "^1.0.1"
graceful-fs@^4.1.11, graceful-fs@^4.1.2:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@ -2578,6 +2611,16 @@ has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
has-symbol-support-x@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.3.0.tgz#588bd6927eaa0e296afae24160659167fc2be4f8"
has-to-string-tag-x@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.3.0.tgz#78e3d98c3c0ec9413e970eb8d766249a1e13058f"
dependencies:
has-symbol-support-x "^1.3.0"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@ -2902,6 +2945,10 @@ is-number@^2.0.2, is-number@^2.1.0:
dependencies:
kind-of "^3.0.2"
is-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
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"
@ -2918,7 +2965,7 @@ is-path-inside@^1.0.0:
dependencies:
path-is-inside "^1.0.1"
is-plain-obj@^1.0.0:
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@ -2950,6 +2997,10 @@ is-resolvable@^1.0.0:
dependencies:
tryit "^1.0.1"
is-retry-allowed@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
is-stream@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@ -3087,6 +3138,13 @@ istanbul@^0.4.5:
which "^1.1.1"
wordwrap "^1.0.0"
isurl@^1.0.0-alpha5:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
dependencies:
has-to-string-tag-x "^1.2.0"
is-object "^1.0.1"
jasmine-core@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.6.3.tgz#45072950e4a42b1e322fe55c001100a465d77815"
@ -3633,6 +3691,10 @@ mime@1.3.4, mime@1.3.x, mime@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
mimic-response@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e"
minimalistic-assert@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
@ -3981,6 +4043,14 @@ osenv@^0.1.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
p-cancelable@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
p-limit@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
@ -3991,6 +4061,12 @@ p-locate@^2.0.0:
dependencies:
p-limit "^1.1.0"
p-timeout@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.0.tgz#9820f99434c5817868b4f34809ee5291660d5b6c"
dependencies:
p-finally "^1.0.0"
package-json@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0"
@ -4419,7 +4495,7 @@ prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
prepend-http@^1.0.0:
prepend-http@^1.0.0, prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@ -5384,6 +5460,10 @@ timed-out@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a"
timed-out@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
timers-browserify@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d"
@ -5545,6 +5625,12 @@ url-loader@^0.5.8:
loader-utils "^1.0.2"
mime "1.3.x"
url-parse-lax@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
dependencies:
prepend-http "^1.0.1"
url-parse@1.0.x:
version "1.0.5"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b"
@ -5559,6 +5645,10 @@ url-parse@^1.0.1, url-parse@^1.1.1:
querystringify "0.0.x"
requires-port "1.0.x"
url-to-options@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@ -5657,9 +5747,11 @@ vue-loader@^11.3.4:
vue-style-loader "^2.0.0"
vue-template-es2015-compiler "^1.2.2"
vue-resource@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-0.9.3.tgz#ab46e1c44ea219142dcc28ae4043b3b04c80959d"
vue-resource@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.4.tgz#9fc0bdf6a2f5cab430129fc99d347b3deae7b099"
dependencies:
got "^7.0.0"
vue-style-loader@^2.0.0:
version "2.0.5"