Commit 29e0cb4b authored by Mike Greiling's avatar Mike Greiling Committed by Alfredo Sumaran

Organize our polyfills and standardize on core-js

parent 88206d67
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
// "Meta+Enter" (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, the form // "Meta+Enter" (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, the form
// is submitted. // is submitted.
// //
require('../extensions/jquery'); import '../commons/bootstrap';
// //
// ### Example Markup // ### Example Markup
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// When called on a form with input fields with the `required` attribute, the // When called on a form with input fields with the `required` attribute, the
// form's submit button will be disabled until all required fields have values. // form's submit button will be disabled until all required fields have values.
// //
require('../extensions/jquery'); import '../commons/bootstrap';
// //
// ### Example Markup // ### Example Markup
......
import 'jquery'; import $ from 'jquery';
// bootstrap jQuery plugins // bootstrap jQuery plugins
import 'bootstrap-sass/assets/javascripts/bootstrap/affix'; import 'bootstrap-sass/assets/javascripts/bootstrap/affix';
...@@ -8,3 +8,9 @@ import 'bootstrap-sass/assets/javascripts/bootstrap/modal'; ...@@ -8,3 +8,9 @@ import 'bootstrap-sass/assets/javascripts/bootstrap/modal';
import 'bootstrap-sass/assets/javascripts/bootstrap/tab'; import 'bootstrap-sass/assets/javascripts/bootstrap/tab';
import 'bootstrap-sass/assets/javascripts/bootstrap/transition'; import 'bootstrap-sass/assets/javascripts/bootstrap/transition';
import 'bootstrap-sass/assets/javascripts/bootstrap/tooltip'; import 'bootstrap-sass/assets/javascripts/bootstrap/tooltip';
// custom jQuery functions
$.fn.extend({
disable() { return $(this).attr('disabled', 'disabled').addClass('disabled'); },
enable() { return $(this).removeAttr('disabled').removeClass('disabled'); },
});
import './polyfills';
import './jquery'; import './jquery';
import './bootstrap'; import './bootstrap';
// ECMAScript polyfills
import 'core-js/fn/array/find';
import 'core-js/fn/object/assign';
import 'core-js/fn/promise';
import 'core-js/fn/string/code-point-at';
import 'core-js/fn/string/from-code-point';
// Browser polyfills
import './polyfills/custom_event';
import './polyfills/element';
if (typeof window.CustomEvent !== 'function') {
window.CustomEvent = function CustomEvent(event, params) {
const evt = document.createEvent('CustomEvent');
const evtParams = params || { bubbles: false, cancelable: false, detail: undefined };
evt.initCustomEvent(event, evtParams.bubbles, evtParams.cancelable, evtParams.detail);
return evt;
};
window.CustomEvent.prototype = Event;
}
/* global Element */ Element.prototype.closest = Element.prototype.closest ||
/* eslint-disable consistent-return, max-len, no-empty, func-names */ function closest(selector, selectedElement = this) {
if (!selectedElement) return null;
Element.prototype.closest = Element.prototype.closest || function closest(selector, selectedElement = this) { return selectedElement.matches(selector) ?
if (!selectedElement) return; selectedElement :
return selectedElement.matches(selector) ? selectedElement : Element.prototype.closest(selector, selectedElement.parentElement); Element.prototype.closest(selector, selectedElement.parentElement);
}; };
Element.prototype.matches = Element.prototype.matches || Element.prototype.matches = Element.prototype.matches ||
Element.prototype.matchesSelector || Element.prototype.matchesSelector ||
...@@ -12,9 +12,9 @@ Element.prototype.matches = Element.prototype.matches || ...@@ -12,9 +12,9 @@ Element.prototype.matches = Element.prototype.matches ||
Element.prototype.msMatchesSelector || Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector || Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector || Element.prototype.webkitMatchesSelector ||
function (s) { function matches(selector) {
const matches = (this.document || this.ownerDocument).querySelectorAll(s); const elms = (this.document || this.ownerDocument).querySelectorAll(selector);
let i = matches.length - 1; let i = elms.length - 1;
while (i >= 0 && matches.item(i) !== this) { i -= 1; } while (i >= 0 && elms.item(i) !== this) { i -= 1; }
return i > -1; return i > -1;
}; };
...@@ -74,6 +74,9 @@ require('../window')(function(w){ ...@@ -74,6 +74,9 @@ require('../window')(function(w){
this._loadUrlData(config.endpoint) this._loadUrlData(config.endpoint)
.then(function(d) { .then(function(d) {
self._loadData(d, config, self); self._loadData(d, config, self);
}, function(xhrError) {
// TODO: properly handle errors due to XHR cancellation
return;
}).catch(function(e) { }).catch(function(e) {
throw new droplabAjaxException(e.message || e); throw new droplabAjaxException(e.message || e);
}); });
......
...@@ -82,6 +82,9 @@ require('../window')(function(w){ ...@@ -82,6 +82,9 @@ require('../window')(function(w){
this._loadUrlData(url) this._loadUrlData(url)
.then(function(data) { .then(function(data) {
self._loadData(data, config, self); self._loadData(data, config, self);
}, function(xhrError) {
// TODO: properly handle errors due to XHR cancellation
return;
}); });
} }
}, },
......
/* eslint-disable no-extend-native, func-names, space-before-function-paren, space-infix-ops, strict, max-len */ // TODO: remove this
'use strict'; // eslint-disable-next-line no-extend-native
Array.prototype.first = function first() {
Array.prototype.first = function() {
return this[0]; return this[0];
}; };
Array.prototype.last = function() { // eslint-disable-next-line no-extend-native
return this[this.length-1]; Array.prototype.last = function last() {
}; return this[this.length - 1];
Array.prototype.find = Array.prototype.find || function(predicate, ...args) {
if (!this) throw new TypeError('Array.prototype.find called on null or undefined');
if (typeof predicate !== 'function') throw new TypeError('predicate must be a function');
const list = Object(this);
const thisArg = args[1];
let value = {};
for (let i = 0; i < list.length; i += 1) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) return value;
}
return undefined;
}; };
/* global CustomEvent */
/* eslint-disable no-global-assign */
// Custom event support for IE
CustomEvent = function CustomEvent(event, parameters) {
const params = parameters || { bubbles: false, cancelable: false, detail: undefined };
const evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
CustomEvent.prototype = window.Event.prototype;
/* eslint-disable func-names, space-before-function-paren, object-shorthand, comma-dangle, max-len */
// Disable an element and add the 'disabled' Bootstrap class
(function() {
$.fn.extend({
disable: function() {
return $(this).attr('disabled', 'disabled').addClass('disabled');
}
});
// Enable an element and remove the 'disabled' Bootstrap class
$.fn.extend({
enable: function() {
return $(this).removeAttr('disabled').removeClass('disabled');
}
});
}).call(window);
/* eslint-disable no-restricted-syntax */
// Adapted from https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
if (typeof Object.assign !== 'function') {
Object.assign = function assign(target, ...args) {
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
const to = Object(target);
for (let index = 0; index < args.length; index += 1) {
const nextSource = args[index];
if (nextSource != null) { // Skip over if undefined or null
for (const nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
import 'string.prototype.codepointat';
import 'string.fromcodepoint';
...@@ -162,6 +162,10 @@ ...@@ -162,6 +162,10 @@
} }
resetDropdowns() { resetDropdowns() {
if (!this.currentDropdown) {
return;
}
// Force current dropdown to hide // Force current dropdown to hide
this.mapping[this.currentDropdown].reference.hideDropdown(); this.mapping[this.currentDropdown].reference.hideDropdown();
......
...@@ -38,7 +38,8 @@ ...@@ -38,7 +38,8 @@
this.editTokenWrapper = this.editToken.bind(this); this.editTokenWrapper = this.editToken.bind(this);
this.tokenChange = this.tokenChange.bind(this); this.tokenChange = this.tokenChange.bind(this);
this.filteredSearchInput.form.addEventListener('submit', this.handleFormSubmit); this.filteredSearchInputForm = this.filteredSearchInput.form;
this.filteredSearchInputForm.addEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper); this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper); this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.addEventListener('input', this.handleInputPlaceholderWrapper); this.filteredSearchInput.addEventListener('input', this.handleInputPlaceholderWrapper);
...@@ -56,7 +57,7 @@ ...@@ -56,7 +57,7 @@
} }
unbindEvents() { unbindEvents() {
this.filteredSearchInput.form.removeEventListener('submit', this.handleFormSubmit); this.filteredSearchInputForm.removeEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper); this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper); this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.removeEventListener('input', this.handleInputPlaceholderWrapper); this.filteredSearchInput.removeEventListener('input', this.handleInputPlaceholderWrapper);
......
...@@ -16,17 +16,9 @@ import Sortable from 'vendor/Sortable'; ...@@ -16,17 +16,9 @@ import Sortable from 'vendor/Sortable';
import 'mousetrap'; import 'mousetrap';
import 'mousetrap/plugins/pause/mousetrap-pause'; import 'mousetrap/plugins/pause/mousetrap-pause';
import 'vendor/fuzzaldrin-plus'; import 'vendor/fuzzaldrin-plus';
import promisePolyfill from 'es6-promise';
// extensions // extensions
import './extensions/string';
import './extensions/array'; import './extensions/array';
import './extensions/custom_event';
import './extensions/element';
import './extensions/jquery';
import './extensions/object';
promisePolyfill.polyfill();
// expose common libraries as globals (TODO: remove these) // expose common libraries as globals (TODO: remove these)
window.jQuery = jQuery; window.jQuery = jQuery;
......
/* eslint-disable no-new*/ /* eslint-disable no-new */
/* global Flash */
import d3 from 'd3'; import d3 from 'd3';
import _ from 'underscore'; import _ from 'underscore';
import statusCodes from '~/lib/utils/http_status'; import statusCodes from '~/lib/utils/http_status';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
import Flash from '~/flash'; import '~/flash';
const prometheusGraphsContainer = '.prometheus-graph'; const prometheusGraphsContainer = '.prometheus-graph';
const metricsEndpoint = 'metrics.json'; const metricsEndpoint = 'metrics.json';
......
---
title: Standardize on core-js for es2015 polyfills
merge_request: 9749
author:
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */
import promisePolyfill from 'es6-promise';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import AwardsHandler from '~/awards_handler'; import AwardsHandler from '~/awards_handler';
promisePolyfill.polyfill();
(function() { (function() {
var awardsHandler, lazyAssert, urlRoot, openAndWaitForEmojiMenu; var awardsHandler, lazyAssert, urlRoot, openAndWaitForEmojiMenu;
......
require('jquery');
require('~/extensions/jquery.js');
require('~/gl_dropdown'); require('~/gl_dropdown');
require('~/lib/utils/type_utility'); require('~/lib/utils/type_utility');
require('~/blob/create_branch_dropdown'); require('~/blob/create_branch_dropdown');
......
require('jquery');
require('~/extensions/jquery.js');
require('~/gl_dropdown'); require('~/gl_dropdown');
require('~/lib/utils/type_utility'); require('~/lib/utils/type_utility');
require('~/blob/create_branch_dropdown'); require('~/blob/create_branch_dropdown');
......
...@@ -8,7 +8,6 @@ import boardNewIssue from '~/boards/components/board_new_issue'; ...@@ -8,7 +8,6 @@ import boardNewIssue from '~/boards/components/board_new_issue';
require('~/boards/models/list'); require('~/boards/models/list');
require('./mock_data'); require('./mock_data');
require('es6-promise').polyfill();
describe('Issue boards new issue form', () => { describe('Issue boards new issue form', () => {
let vm; let vm;
......
...@@ -15,7 +15,6 @@ require('~/boards/models/user'); ...@@ -15,7 +15,6 @@ require('~/boards/models/user');
require('~/boards/services/board_service'); require('~/boards/services/board_service');
require('~/boards/stores/boards_store'); require('~/boards/stores/boards_store');
require('./mock_data'); require('./mock_data');
require('es6-promise').polyfill();
describe('Store', () => { describe('Store', () => {
beforeEach(() => { beforeEach(() => {
......
/* eslint-disable space-before-function-paren, no-var */ /* eslint-disable space-before-function-paren, no-var */
require('~/extensions/jquery'); import '~/commons/bootstrap';
(function() { (function() {
describe('jQuery extensions', function() { describe('Bootstrap jQuery extensions', function() {
describe('disable', function() { describe('disable', function() {
beforeEach(function() { beforeEach(function() {
return setFixtures('<input type="text" />'); return setFixtures('<input type="text" />');
......
...@@ -18,28 +18,5 @@ require('~/extensions/array'); ...@@ -18,28 +18,5 @@ require('~/extensions/array');
return expect(arr.last()).toBe(5); return expect(arr.last()).toBe(5);
}); });
}); });
describe('find', function () {
beforeEach(() => {
this.arr = [0, 1, 2, 3, 4, 5];
});
it('returns the item that first passes the predicate function', () => {
expect(this.arr.find(item => item === 2)).toBe(2);
});
it('returns undefined if no items pass the predicate function', () => {
expect(this.arr.find(item => item === 6)).not.toBeDefined();
});
it('error when called on undefined or null', () => {
expect(Array.prototype.find.bind(undefined, item => item === 1)).toThrow();
expect(Array.prototype.find.bind(null, item => item === 1)).toThrow();
});
it('error when predicate is not a function', () => {
expect(Array.prototype.find.bind(this.arr, 1)).toThrow();
});
});
}); });
}).call(window); }).call(window);
require('~/extensions/element');
(() => {
describe('Element extensions', function () {
beforeEach(() => {
this.element = document.createElement('ul');
});
describe('matches', () => {
it('returns true if element matches the selector', () => {
expect(this.element.matches('ul')).toBeTruthy();
});
it("returns false if element doesn't match the selector", () => {
expect(this.element.matches('.not-an-element')).toBeFalsy();
});
});
describe('closest', () => {
beforeEach(() => {
this.childElement = document.createElement('li');
this.element.appendChild(this.childElement);
});
it('returns the closest parent that matches the selector', () => {
expect(this.childElement.closest('ul').toString()).toBe(this.element.toString());
});
it('returns itself if it matches the selector', () => {
expect(this.childElement.closest('li').toString()).toBe(this.childElement.toString());
});
it('returns undefined if nothing matches the selector', () => {
expect(this.childElement.closest('.no-an-element')).toBeFalsy();
});
});
});
})();
require('~/extensions/object');
describe('Object extensions', () => {
describe('assign', () => {
it('merges source object into target object', () => {
const targetObj = {};
const sourceObj = {
foo: 'bar',
};
Object.assign(targetObj, sourceObj);
expect(targetObj.foo).toBe('bar');
});
it('merges object with the same properties', () => {
const targetObj = {
foo: 'bar',
};
const sourceObj = {
foo: 'baz',
};
Object.assign(targetObj, sourceObj);
expect(targetObj.foo).toBe('baz');
});
});
});
...@@ -41,7 +41,6 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper ...@@ -41,7 +41,6 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper
</div> </div>
`); `);
spyOn(gl.FilteredSearchManager.prototype, 'cleanup').and.callFake(() => {});
spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {}); spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {});
spyOn(gl.FilteredSearchManager.prototype, 'tokenChange').and.callFake(() => {}); spyOn(gl.FilteredSearchManager.prototype, 'tokenChange').and.callFake(() => {});
spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {}); spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {});
...@@ -54,6 +53,10 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper ...@@ -54,6 +53,10 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper
manager = new gl.FilteredSearchManager(); manager = new gl.FilteredSearchManager();
}); });
afterEach(() => {
manager.cleanup();
});
describe('search', () => { describe('search', () => {
const defaultParams = '?scope=all&utf8=✓&state=opened'; const defaultParams = '?scope=all&utf8=✓&state=opened';
......
import '~/extensions/string';
import '~/extensions/array';
import { glEmojiTag } from '~/behaviors/gl_emoji'; import { glEmojiTag } from '~/behaviors/gl_emoji';
import { import {
isEmojiUnicodeSupported, isEmojiUnicodeSupported,
......
import 'jquery'; import 'jquery';
import es6Promise from 'es6-promise';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
import PrometheusGraph from '~/monitoring/prometheus_graph'; import PrometheusGraph from '~/monitoring/prometheus_graph';
import { prometheusMockData } from './prometheus_mock_data'; import { prometheusMockData } from './prometheus_mock_data';
es6Promise.polyfill();
describe('PrometheusGraph', () => { describe('PrometheusGraph', () => {
const fixtureName = 'static/environments/metrics.html.raw'; const fixtureName = 'static/environments/metrics.html.raw';
const prometheusGraphContainer = '.prometheus-graph'; const prometheusGraphContainer = '.prometheus-graph';
......
import '~/commons/polyfills/element';
describe('Element polyfills', function () {
beforeEach(() => {
this.element = document.createElement('ul');
});
describe('matches', () => {
it('returns true if element matches the selector', () => {
expect(this.element.matches('ul')).toBeTruthy();
});
it("returns false if element doesn't match the selector", () => {
expect(this.element.matches('.not-an-element')).toBeFalsy();
});
});
describe('closest', () => {
beforeEach(() => {
this.childElement = document.createElement('li');
this.element.appendChild(this.childElement);
});
it('returns the closest parent that matches the selector', () => {
expect(this.childElement.closest('ul').toString()).toBe(this.element.toString());
});
it('returns itself if it matches the selector', () => {
expect(this.childElement.closest('li').toString()).toBe(this.childElement.toString());
});
it('returns undefined if nothing matches the selector', () => {
expect(this.childElement.closest('.no-an-element')).toBeFalsy();
});
});
});
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */
/* global Sidebar */ /* global Sidebar */
require('~/right_sidebar'); import '~/commons/bootstrap';
require('~/extensions/jquery.js'); import '~/right_sidebar';
(function() { (function() {
var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState; var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState;
......
...@@ -31,13 +31,9 @@ require('~/shortcuts_issuable'); ...@@ -31,13 +31,9 @@ require('~/shortcuts_issuable');
this.shortcut.replyWithSelectedText(); this.shortcut.replyWithSelectedText();
expect($(this.selector).val()).toBe(''); expect($(this.selector).val()).toBe('');
}); });
it('triggers `input`', function() { it('triggers `focus`', function() {
var focused = false;
$(this.selector).on('focus', function() {
focused = true;
});
this.shortcut.replyWithSelectedText(); this.shortcut.replyWithSelectedText();
expect(focused).toBe(true); expect(document.activeElement).toBe(document.querySelector(this.selector));
}); });
}); });
describe('with any selection', function() { describe('with any selection', function() {
......
...@@ -1213,7 +1213,7 @@ cookie@0.3.1: ...@@ -1213,7 +1213,7 @@ cookie@0.3.1:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
core-js@^2.2.0, core-js@^2.4.0: core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
...@@ -1553,7 +1553,7 @@ es6-map@^0.1.3: ...@@ -1553,7 +1553,7 @@ es6-map@^0.1.3:
es6-symbol "~3.1.0" es6-symbol "~3.1.0"
event-emitter "~0.3.4" event-emitter "~0.3.4"
es6-promise@^4.0.5, es6-promise@~4.0.3: es6-promise@~4.0.3:
version "4.0.5" version "4.0.5"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42"
...@@ -4123,14 +4123,6 @@ string-width@^2.0.0: ...@@ -4123,14 +4123,6 @@ string-width@^2.0.0:
is-fullwidth-code-point "^2.0.0" is-fullwidth-code-point "^2.0.0"
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
string.fromcodepoint@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz#8d978333c0bc92538f50f383e4888f3e5619d653"
string.prototype.codepointat@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78"
string_decoder@^0.10.25, string_decoder@~0.10.x: string_decoder@^0.10.25, string_decoder@~0.10.x:
version "0.10.31" version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment