Last active
November 2, 2021 11:38
-
-
Save seyoon20087/87861e753c1f1fab0c3af506585dc901 to your computer and use it in GitHub Desktop.
a patch for boostrap to be ssr friendly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -u ./bootstrap/js/src/base-component.js ./bootstrap-ssr-friendly/js/src/base-component.js | |
--- ./bootstrap/js/src/base-component.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/base-component.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -8,7 +8,9 @@ | |
import Data from './dom/data' | |
import { | |
executeAfterTransition, | |
- getElement | |
+ getElement, | |
+ getWindow, | |
+ getDocument | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
@@ -31,6 +33,8 @@ | |
} | |
this._element = element | |
+ this._window = getWindow() | |
+ this._document = getDocument() | |
Data.set(this._element, this.constructor.DATA_KEY, this) | |
} | |
diff -u ./bootstrap/js/src/button.js ./bootstrap-ssr-friendly/js/src/button.js | |
--- ./bootstrap/js/src/button.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/button.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -5,7 +5,7 @@ | |
* -------------------------------------------------------------------------- | |
*/ | |
-import { defineJQueryPlugin } from './util/index' | |
+import { defineJQueryPlugin, getDocument } from './util/index' | |
import EventHandler from './dom/event-handler' | |
import BaseComponent from './base-component' | |
@@ -54,7 +54,7 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => { | |
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => { | |
event.preventDefault() | |
const button = event.target.closest(SELECTOR_DATA_TOGGLE) | |
diff -u ./bootstrap/js/src/carousel.js ./bootstrap-ssr-friendly/js/src/carousel.js | |
--- ./bootstrap/js/src/carousel.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/carousel.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -13,7 +13,9 @@ | |
isVisible, | |
reflow, | |
triggerTransitionEnd, | |
- typeCheckConfig | |
+ typeCheckConfig, | |
+ getDocument, | |
+ getWindow | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
import Manipulator from './dom/manipulator' | |
@@ -127,7 +129,7 @@ | |
nextWhenVisible() { | |
// Don't call next when the page isn't visible | |
// or the carousel or its parent isn't visible | |
- if (!document.hidden && isVisible(this._element)) { | |
+ if (!this._document.hidden && isVisible(this._element)) { | |
this.next() | |
} | |
} | |
@@ -164,7 +166,7 @@ | |
this._updateInterval() | |
this._interval = setInterval( | |
- (document.visibilityState ? this.nextWhenVisible : this.next).bind(this), | |
+ (this._document.visibilityState ? this.nextWhenVisible : this.next).bind(this), | |
this._config.interval | |
) | |
} | |
@@ -509,9 +511,9 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler) | |
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler) | |
-EventHandler.on(window, EVENT_LOAD_DATA_API, () => { | |
+EventHandler.on(getWindow(), EVENT_LOAD_DATA_API, () => { | |
const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE) | |
for (const carousel of carousels) { | |
diff -u ./bootstrap/js/src/collapse.js ./bootstrap-ssr-friendly/js/src/collapse.js | |
--- ./bootstrap/js/src/collapse.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/collapse.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -11,7 +11,8 @@ | |
getElementFromSelector, | |
getSelectorFromElement, | |
reflow, | |
- typeCheckConfig | |
+ typeCheckConfig, | |
+ getDocument | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
import Manipulator from './dom/manipulator' | |
@@ -289,7 +290,7 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element | |
if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) { | |
event.preventDefault() | |
Common subdirectories: ./bootstrap/js/src/dom and ./bootstrap-ssr-friendly/js/src/dom | |
diff -u ./bootstrap/js/src/dropdown.js ./bootstrap-ssr-friendly/js/src/dropdown.js | |
--- ./bootstrap/js/src/dropdown.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/dropdown.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -16,7 +16,8 @@ | |
isRTL, | |
isVisible, | |
noop, | |
- typeCheckConfig | |
+ typeCheckConfig, | |
+ getDocument | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
import Manipulator from './dom/manipulator' | |
@@ -144,8 +145,8 @@ | |
// empty mouseover listeners to the body's immediate children; | |
// only needed because of broken event delegation on iOS | |
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html | |
- if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) { | |
- for (const elem of [].concat(...document.body.children)) { | |
+ if ('ontouchstart' in this._document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) { | |
+ for (const elem of [].concat(...this._document.body.children)) { | |
EventHandler.on(elem, 'mouseover', noop) | |
} | |
} | |
@@ -468,11 +469,13 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler) | |
-EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler) | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus) | |
-EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus) | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
+const documentRef = getDocument() | |
+ | |
+EventHandler.on(documentRef, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler) | |
+EventHandler.on(documentRef, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler) | |
+EventHandler.on(documentRef, EVENT_CLICK_DATA_API, Dropdown.clearMenus) | |
+EventHandler.on(documentRef, EVENT_KEYUP_DATA_API, Dropdown.clearMenus) | |
+EventHandler.on(documentRef, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
event.preventDefault() | |
Dropdown.getOrCreateInstance(this).toggle() | |
}) | |
diff -u ./bootstrap/js/src/modal.js ./bootstrap-ssr-friendly/js/src/modal.js | |
--- ./bootstrap/js/src/modal.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/modal.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -11,7 +11,8 @@ | |
isRTL, | |
isVisible, | |
reflow, | |
- typeCheckConfig | |
+ typeCheckConfig, | |
+ getDocument | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
import Manipulator from './dom/manipulator' | |
@@ -212,7 +213,7 @@ | |
if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { | |
// Don't move modal's DOM position | |
- document.body.append(this._element) | |
+ this._document.body.append(this._element) | |
} | |
this._element.style.display = 'block' | |
@@ -275,7 +276,7 @@ | |
this._element.removeAttribute('role') | |
this._isTransitioning = false | |
this._backdrop.hide(() => { | |
- document.body.classList.remove(CLASS_NAME_OPEN) | |
+ this._document.body.classList.remove(CLASS_NAME_OPEN) | |
this._resetAdjustments() | |
this._scrollBar.reset() | |
EventHandler.trigger(this._element, EVENT_HIDDEN) | |
@@ -314,7 +315,7 @@ | |
} | |
const { classList, scrollHeight, style } = this._element | |
- const isModalOverflowing = scrollHeight > document.documentElement.clientHeight | |
+ const isModalOverflowing = scrollHeight > this._document.documentElement.clientHeight | |
// return if the following background transition hasn't yet completed | |
if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) { | |
@@ -343,7 +344,7 @@ | |
*/ | |
_adjustDialog() { | |
- const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight | |
+ const isModalOverflowing = this._element.scrollHeight > this._document.documentElement.clientHeight | |
const scrollbarWidth = this._scrollBar.getWidth() | |
const isBodyOverflowing = scrollbarWidth > 0 | |
@@ -383,7 +384,7 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
const target = getElementFromSelector(this) | |
if (['A', 'AREA'].includes(this.tagName)) { | |
@@ -403,7 +404,7 @@ | |
}) | |
}) | |
- // avoid conflict when clicking moddal toggler while another one is open | |
+ // avoid conflict when clicking modal toggler while another one is open | |
const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR) | |
if (allReadyOpen) { | |
Modal.getInstance(allReadyOpen).hide() | |
diff -u ./bootstrap/js/src/offcanvas.js ./bootstrap-ssr-friendly/js/src/offcanvas.js | |
--- ./bootstrap/js/src/offcanvas.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/offcanvas.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -10,7 +10,9 @@ | |
getElementFromSelector, | |
isDisabled, | |
isVisible, | |
- typeCheckConfig | |
+ typeCheckConfig, | |
+ getDocument, | |
+ getWindow | |
} from './util/index' | |
import ScrollBarHelper from './util/scrollbar' | |
import EventHandler from './dom/event-handler' | |
@@ -218,7 +220,7 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
const target = getElementFromSelector(this) | |
if (['A', 'AREA'].includes(this.tagName)) { | |
@@ -246,7 +248,7 @@ | |
data.toggle(this) | |
}) | |
-EventHandler.on(window, EVENT_LOAD_DATA_API, () => { | |
+EventHandler.on(getWindow(), EVENT_LOAD_DATA_API, () => { | |
for (const el of SelectorEngine.find(OPEN_SELECTOR)) { | |
Offcanvas.getOrCreateInstance(el).show() | |
} | |
diff -u ./bootstrap/js/src/scrollspy.js ./bootstrap-ssr-friendly/js/src/scrollspy.js | |
--- ./bootstrap/js/src/scrollspy.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/scrollspy.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -9,7 +9,8 @@ | |
defineJQueryPlugin, | |
getElement, | |
getSelectorFromElement, | |
- typeCheckConfig | |
+ typeCheckConfig, | |
+ getWindow | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
import Manipulator from './dom/manipulator' | |
@@ -63,7 +64,7 @@ | |
class ScrollSpy extends BaseComponent { | |
constructor(element, config) { | |
super(element) | |
- this._scrollElement = this._element.tagName === 'BODY' ? window : this._element | |
+ this._scrollElement = this._element.tagName === 'BODY' ? this._window : this._element | |
this._config = this._getConfig(config) | |
this._offsets = [] | |
this._targets = [] | |
@@ -157,14 +158,14 @@ | |
_getScrollHeight() { | |
return this._scrollElement.scrollHeight || Math.max( | |
- document.body.scrollHeight, | |
- document.documentElement.scrollHeight | |
+ this._document.body.scrollHeight, | |
+ this._document.documentElement.scrollHeight | |
) | |
} | |
_getOffsetHeight() { | |
return this._scrollElement === window ? | |
- window.innerHeight : | |
+ this._window.innerHeight : | |
this._scrollElement.getBoundingClientRect().height | |
} | |
@@ -271,7 +272,7 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(window, EVENT_LOAD_DATA_API, () => { | |
+EventHandler.on(getWindow(), EVENT_LOAD_DATA_API, () => { | |
for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) { | |
new ScrollSpy(spy) // eslint-disable-line no-new | |
} | |
diff -u ./bootstrap/js/src/tab.js ./bootstrap-ssr-friendly/js/src/tab.js | |
--- ./bootstrap/js/src/tab.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/tab.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -9,7 +9,8 @@ | |
defineJQueryPlugin, | |
getElementFromSelector, | |
isDisabled, | |
- reflow | |
+ reflow, | |
+ getDocument | |
} from './util/index' | |
import EventHandler from './dom/event-handler' | |
import SelectorEngine from './dom/selector-engine' | |
@@ -184,7 +185,7 @@ | |
* Data API implementation | |
*/ | |
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { | |
if (['A', 'AREA'].includes(this.tagName)) { | |
event.preventDefault() | |
} | |
diff -u ./bootstrap/js/src/tooltip.js ./bootstrap-ssr-friendly/js/src/tooltip.js | |
--- ./bootstrap/js/src/tooltip.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/tooltip.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -277,8 +277,8 @@ | |
// empty mouseover listeners to the body's immediate children; | |
// only needed because of broken event delegation on iOS | |
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html | |
- if ('ontouchstart' in document.documentElement) { | |
- for (const element of [].concat(...document.body.children)) { | |
+ if ('ontouchstart' in this._document.documentElement) { | |
+ for (const element of [].concat(...this._document.body.children)) { | |
EventHandler.on(element, 'mouseover', noop) | |
} | |
} | |
@@ -329,8 +329,8 @@ | |
// If this is a touch-enabled device we remove the extra | |
// empty mouseover listeners we added for iOS support | |
- if ('ontouchstart' in document.documentElement) { | |
- for (const element of [].concat(...document.body.children)) { | |
+ if ('ontouchstart' in this._document.documentElement) { | |
+ for (const element of [].concat(...this._document.body.children)) { | |
EventHandler.off(element, 'mouseover', noop) | |
} | |
} | |
@@ -360,7 +360,7 @@ | |
return this.tip | |
} | |
- const element = document.createElement('div') | |
+ const element = this._document.createElement('div') | |
element.innerHTML = this._config.template | |
const tip = element.children[0] | |
Common subdirectories: ./bootstrap/js/src/util and ./bootstrap-ssr-friendly/js/src/util | |
diff -u ./bootstrap/js/src/util/component-functions.js ./bootstrap-ssr-friendly/js/src/util/component-functions.js | |
--- ./bootstrap/js/src/util/component-functions.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/util/component-functions.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -6,13 +6,13 @@ | |
*/ | |
import EventHandler from '../dom/event-handler' | |
-import { getElementFromSelector, isDisabled } from './index' | |
+import { getElementFromSelector, isDisabled, getDocument } from './index' | |
const enableDismissTrigger = (component, method = 'hide') => { | |
const clickEvent = `click.dismiss${component.EVENT_KEY}` | |
const name = component.NAME | |
- EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { | |
+ EventHandler.on(getDocument(), clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { | |
if (['A', 'AREA'].includes(this.tagName)) { | |
event.preventDefault() | |
} | |
diff -u ./bootstrap/js/src/util/index.js ./bootstrap-ssr-friendly/js/src/util/index.js | |
--- ./bootstrap/js/src/util/index.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/util/index.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -25,7 +25,7 @@ | |
const getUID = prefix => { | |
do { | |
prefix += Math.floor(Math.random() * MAX_UID) | |
- } while (document.getElementById(prefix)) | |
+ } while (getDocument().getElementById(prefix)) | |
return prefix | |
} | |
@@ -59,7 +59,7 @@ | |
const selector = getSelector(element) | |
if (selector) { | |
- return document.querySelector(selector) ? selector : null | |
+ return getDocument().querySelector(selector) ? selector : null | |
} | |
return null | |
@@ -68,7 +68,7 @@ | |
const getElementFromSelector = element => { | |
const selector = getSelector(element) | |
- return selector ? document.querySelector(selector) : null | |
+ return selector ? getDocument().querySelector(selector) : null | |
} | |
const getTransitionDurationFromElement = element => { | |
@@ -77,7 +77,7 @@ | |
} | |
// Get transition-duration of the element | |
- let { transitionDuration, transitionDelay } = window.getComputedStyle(element) | |
+ let { transitionDuration, transitionDelay } = getWindow().getComputedStyle(element) | |
const floatTransitionDuration = Number.parseFloat(transitionDuration) | |
const floatTransitionDelay = Number.parseFloat(transitionDelay) | |
@@ -162,7 +162,7 @@ | |
} | |
const findShadowRoot = element => { | |
- if (!document.documentElement.attachShadow) { | |
+ if (!getDocument().documentElement.attachShadow) { | |
return null | |
} | |
@@ -195,13 +195,14 @@ | |
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation | |
*/ | |
const reflow = element => { | |
- element.offsetHeight // eslint-disable-line no-unused-expressions | |
+ // eslint-disable-next-line no-unused-expressions | |
+ element.offsetHeight | |
} | |
const getjQuery = () => { | |
const { jQuery } = window | |
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { | |
+ if (jQuery && !getDocument().body.hasAttribute('data-bs-no-jquery')) { | |
return jQuery | |
} | |
@@ -211,10 +212,10 @@ | |
const DOMContentLoadedCallbacks = [] | |
const onDOMContentLoaded = callback => { | |
- if (document.readyState === 'loading') { | |
+ if (getDocument().readyState === 'loading') { | |
// add listener on the first call when the document is in loading state | |
if (!DOMContentLoadedCallbacks.length) { | |
- document.addEventListener('DOMContentLoaded', () => { | |
+ getDocument().addEventListener('DOMContentLoaded', () => { | |
for (const callback of DOMContentLoadedCallbacks) { | |
callback() | |
} | |
@@ -227,7 +228,7 @@ | |
} | |
} | |
-const isRTL = () => document.documentElement.dir === 'rtl' | |
+const isRTL = () => getDocument().documentElement.dir === 'rtl' | |
const defineJQueryPlugin = plugin => { | |
onDOMContentLoaded(() => { | |
@@ -309,11 +310,26 @@ | |
return list[Math.max(0, Math.min(index, listLength - 1))] | |
} | |
+/** | |
+ * @return {window|{}} The proper element | |
+ */ | |
+const getWindow = () => { | |
+ return typeof window !== 'undefined' ? window : {} | |
+} | |
+ | |
+/** | |
+ * @return {document|{}} The proper element | |
+ */ | |
+const getDocument = () => { | |
+ return typeof document !== 'undefined' ? document : {} | |
+} | |
+ | |
export { | |
defineJQueryPlugin, | |
execute, | |
executeAfterTransition, | |
findShadowRoot, | |
+ getDocument, | |
getElement, | |
getElementFromSelector, | |
getjQuery, | |
@@ -321,6 +337,7 @@ | |
getSelectorFromElement, | |
getTransitionDurationFromElement, | |
getUID, | |
+ getWindow, | |
isDisabled, | |
isElement, | |
isRTL, | |
diff -u ./bootstrap/js/src/util/sanitizer.js ./bootstrap-ssr-friendly/js/src/util/sanitizer.js | |
--- ./bootstrap/js/src/util/sanitizer.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/util/sanitizer.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -5,6 +5,8 @@ | |
* -------------------------------------------------------------------------- | |
*/ | |
+import { getWindow } from './index' | |
+ | |
const uriAttributes = new Set([ | |
'background', | |
'cite', | |
@@ -91,7 +93,8 @@ | |
return sanitizeFn(unsafeHtml) | |
} | |
- const domParser = new window.DOMParser() | |
+ const windowRef = getWindow() | |
+ const domParser = new windowRef.DOMParser() | |
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html') | |
const elements = [].concat(...createdDocument.body.querySelectorAll('*')) | |
diff -u ./bootstrap/js/src/util/scrollbar.js ./bootstrap-ssr-friendly/js/src/util/scrollbar.js | |
--- ./bootstrap/js/src/util/scrollbar.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/util/scrollbar.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -7,7 +7,7 @@ | |
import SelectorEngine from '../dom/selector-engine' | |
import Manipulator from '../dom/manipulator' | |
-import { isElement } from './index' | |
+import { isElement, getDocument } from './index' | |
/** | |
* Constants | |
@@ -22,7 +22,7 @@ | |
class ScrollBarHelper { | |
constructor() { | |
- this._element = document.body | |
+ this._element = getDocument().body | |
} | |
// Public | |
diff -u ./bootstrap/js/src/util/swipe.js ./bootstrap-ssr-friendly/js/src/util/swipe.js | |
--- ./bootstrap/js/src/util/swipe.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/util/swipe.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -6,7 +6,7 @@ | |
*/ | |
import EventHandler from '../dom/event-handler' | |
-import { execute, typeCheckConfig } from './index' | |
+import { execute, getDocument, getWindow, typeCheckConfig } from './index' | |
/** | |
* Constants | |
@@ -50,7 +50,7 @@ | |
this._config = this._getConfig(config) | |
this._deltaX = 0 | |
- this._supportPointerEvents = Boolean(window.PointerEvent) | |
+ this._supportPointerEvents = Boolean(getWindow().PointerEvent) | |
this._initEvents() | |
} | |
@@ -133,7 +133,7 @@ | |
// Static | |
static isSupported() { | |
- return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 | |
+ return 'ontouchstart' in getDocument().documentElement || navigator.maxTouchPoints > 0 | |
} | |
} | |
diff -u ./bootstrap/js/src/dom/event-handler.js ./bootstrap-ssr-friendly/js/src/dom/event-handler.js | |
--- ./bootstrap/js/src/dom/event-handler.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/dom/event-handler.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -5,7 +5,7 @@ | |
* -------------------------------------------------------------------------- | |
*/ | |
-import { getjQuery } from '../util/index' | |
+import { getjQuery, getDocument } from '../util/index' | |
/** | |
* Constants | |
@@ -302,7 +302,7 @@ | |
} | |
if (isNative) { | |
- evt = document.createEvent('HTMLEvents') | |
+ evt = getDocument().createEvent('HTMLEvents') | |
evt.initEvent(typeEvent, bubbles, true) | |
} else { | |
evt = new CustomEvent(event, { bubbles, cancelable: true }) | |
diff -u ./bootstrap/js/src/dom/manipulator.js ./bootstrap-ssr-friendly/js/src/dom/manipulator.js | |
--- ./bootstrap/js/src/dom/manipulator.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/dom/manipulator.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -5,6 +5,8 @@ | |
* -------------------------------------------------------------------------- | |
*/ | |
+import { getWindow } from '../util/index' | |
+ | |
function normalizeData(val) { | |
if (val === 'true') { | |
return true | |
@@ -61,10 +63,11 @@ | |
offset(element) { | |
const rect = element.getBoundingClientRect() | |
+ const windowRef = getWindow() | |
return { | |
- top: rect.top + window.pageYOffset, | |
- left: rect.left + window.pageXOffset | |
+ top: rect.top + windowRef.pageYOffset, | |
+ left: rect.left + windowRef.pageXOffset | |
} | |
}, | |
diff -u ./bootstrap/js/src/dom/selector-engine.js ./bootstrap-ssr-friendly/js/src/dom/selector-engine.js | |
--- ./bootstrap/js/src/dom/selector-engine.js 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/js/src/dom/selector-engine.js 2021-11-02 20:30:24.000000000 +0900 | |
@@ -5,7 +5,7 @@ | |
* -------------------------------------------------------------------------- | |
*/ | |
-import { isDisabled, isVisible } from '../util/index' | |
+import { getDocument, isDisabled, isVisible } from '../util/index' | |
/** | |
* Constants | |
@@ -14,11 +14,11 @@ | |
const NODE_TEXT = 3 | |
const SelectorEngine = { | |
- find(selector, element = document.documentElement) { | |
+ find(selector, element = getDocument().documentElement) { | |
return [].concat(...Element.prototype.querySelectorAll.call(element, selector)) | |
}, | |
- findOne(selector, element = document.documentElement) { | |
+ findOne(selector, element = getDocument().documentElement) { | |
return Element.prototype.querySelector.call(element, selector) | |
}, | |
--- ./bootstrap/package.json 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/package.json 2021-11-02 20:30:24.000000000 +0900 | |
@@ -116,6 +116,7 @@ | |
"eslint": "^8.1.0", | |
"eslint-config-xo": "^0.39.0", | |
"eslint-plugin-import": "^2.25.2", | |
+ "eslint-plugin-ssr-friendly": "^1.0.5", | |
"eslint-plugin-unicorn": "^37.0.1", | |
"find-unused-sass-variables": "^3.1.0", | |
"glob": "^7.2.0", | |
--- ./bootstrap/.eslintrc.json 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/.eslintrc.json 2021-11-02 20:30:24.000000000 +0900 | |
@@ -61,5 +61,18 @@ | |
"unicorn/prefer-query-selector": "off", | |
"unicorn/prefer-spread": "off", | |
"unicorn/prevent-abbreviations": "off" | |
- } | |
+ }, | |
+ "overrides": [ | |
+ { | |
+ "files": "js/src/**/*.js", | |
+ "plugins": ["ssr-friendly"], | |
+ "extends": [ | |
+ "plugin:ssr-friendly/recommended" | |
+ ], | |
+ "rules": { | |
+ "ssr-friendly/no-dom-globals-in-react-cc-render": "off", | |
+ "ssr-friendly/no-dom-globals-in-react-fc": "off" | |
+ } | |
+ } | |
+ ] | |
} | |
--- ./bootstrap/package-lock.json 2021-11-02 20:30:03.000000000 +0900 | |
+++ ./bootstrap-ssr-friendly/package-lock.json 2021-11-02 20:34:52.000000000 +0900 | |
@@ -25,6 +25,7 @@ | |
"eslint": "^8.1.0", | |
"eslint-config-xo": "^0.39.0", | |
"eslint-plugin-import": "^2.25.2", | |
+ "eslint-plugin-ssr-friendly": "^1.0.5", | |
"eslint-plugin-unicorn": "^37.0.1", | |
"find-unused-sass-variables": "^3.1.0", | |
"glob": "^7.2.0", | |
@@ -1684,9 +1685,9 @@ | |
} | |
}, | |
"node_modules/@cspell/cspell-bundled-dicts": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.4.tgz", | |
- "integrity": "sha512-+rbeDNGVX9kYF6ARNLyCRL0lHsS0Kxwb38Dk9bPk/qx3HeKjrVfg6mupFH+kTDWJFCh+ua3D07yPc3TZzcdVIg==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.5.tgz", | |
+ "integrity": "sha512-uuoAYkw1O+AcHx16XN8u42eCm4yLgT0D9vOWnrOKJEScpIvyrgHbL/B71PAkmeTwfhPWhyHb3m/QjYXzio3Olw==", | |
"dev": true, | |
"dependencies": { | |
"@cspell/dict-ada": "^1.1.2", | |
@@ -1700,7 +1701,7 @@ | |
"@cspell/dict-django": "^1.0.26", | |
"@cspell/dict-dotnet": "^1.0.32", | |
"@cspell/dict-elixir": "^1.0.26", | |
- "@cspell/dict-en_us": "^2.1.2", | |
+ "@cspell/dict-en_us": "^2.1.3", | |
"@cspell/dict-en-gb": "^1.1.33", | |
"@cspell/dict-filetypes": "^2.0.1", | |
"@cspell/dict-fonts": "^1.0.14", | |
@@ -3952,17 +3953,17 @@ | |
} | |
}, | |
"node_modules/cspell": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.4.tgz", | |
- "integrity": "sha512-O0jA0Hd6AfBJHLATsQ0QUSDrjcDCUsrWMQSBjqK6EEJKZhZjoBDCKrgJqh8Qp3MvLIgHqq4r75JrsfRk5SZwhQ==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.5.tgz", | |
+ "integrity": "sha512-jfHJ5/TpQ2qrP8K474GoW6axMhkbBx4q2P4TojbkSaDQ/KrvXJjPvvGDYBzCTwu0RyosiLEiJfdyUohGi76eLw==", | |
"dev": true, | |
"dependencies": { | |
"chalk": "^4.1.2", | |
"commander": "^8.3.0", | |
"comment-json": "^4.1.1", | |
- "cspell-gitignore": "^5.12.4", | |
+ "cspell-gitignore": "^5.12.5", | |
"cspell-glob": "^5.12.4", | |
- "cspell-lib": "^5.12.4", | |
+ "cspell-lib": "^5.12.5", | |
"fast-json-stable-stringify": "^2.1.0", | |
"file-entry-cache": "^6.0.1", | |
"fs-extra": "^10.0.0", | |
@@ -3983,9 +3984,9 @@ | |
} | |
}, | |
"node_modules/cspell-gitignore": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.4.tgz", | |
- "integrity": "sha512-a5pK6gFEtcGAEESV74m21KvRi0afMw3QE2WXcC0v2lHYyHyHeDK/eLQbk8cVSbuMTaXgDyFtyBwSP7Qq0PAnFg==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.5.tgz", | |
+ "integrity": "sha512-I1QizO6LSSpeaEzBjtmcPu09l7bMvvUsVhsHWtzp6RVz3DXQq/ntn/s5HPGCcRVTXO9eeRePTy1LfOsHZO1cMQ==", | |
"dev": true, | |
"dependencies": { | |
"cspell-glob": "^5.12.4", | |
@@ -4020,12 +4021,12 @@ | |
} | |
}, | |
"node_modules/cspell-lib": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.4.tgz", | |
- "integrity": "sha512-NqmQ1j5PsQZJxUqdPaEMrNSKmIiaWSQVzITGfW08FEiTCqSpHxRQdNMM6B7nYUS0NgS5wYwycNMkEWaRQebI+Q==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.5.tgz", | |
+ "integrity": "sha512-7pPFWrojoeQnYchFKLBpeF+39ZKIyLuuneydZCaOIFGzUwyKX6uK4Cfz9rEs0CBLqXqlsectm9WOloW3KTs8KA==", | |
"dev": true, | |
"dependencies": { | |
- "@cspell/cspell-bundled-dicts": "^5.12.4", | |
+ "@cspell/cspell-bundled-dicts": "^5.12.5", | |
"@cspell/cspell-types": "^5.12.4", | |
"clear-module": "^4.1.1", | |
"comment-json": "^4.1.1", | |
@@ -4033,7 +4034,7 @@ | |
"cosmiconfig": "^7.0.1", | |
"cspell-glob": "^5.12.4", | |
"cspell-io": "^5.12.4", | |
- "cspell-trie-lib": "^5.12.4", | |
+ "cspell-trie-lib": "^5.12.5", | |
"find-up": "^5.0.0", | |
"fs-extra": "^10.0.0", | |
"gensequence": "^3.1.1", | |
@@ -4047,9 +4048,9 @@ | |
} | |
}, | |
"node_modules/cspell-trie-lib": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.4.tgz", | |
- "integrity": "sha512-WXnqSVyqP7ZhRWxF3C4olXATETyxD+43f0T0Jzlq0Dz8nxXmzEl79Ws9sEZo4ssLTMXaEcx4Uh361vQYZY+irA==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.5.tgz", | |
+ "integrity": "sha512-oF2LR860BhKISIyQ8FSzq7a+dB9fbFcYP42LeO8NsXk0qhv9gTR3ReiyA1rcp9ocClpg26AhU08dNuAxcHQBmA==", | |
"dev": true, | |
"dependencies": { | |
"fs-extra": "^10.0.0", | |
@@ -5083,6 +5084,45 @@ | |
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", | |
"dev": true | |
}, | |
+ "node_modules/eslint-plugin-ssr-friendly": { | |
+ "version": "1.0.5", | |
+ "resolved": "https://registry.npmjs.org/eslint-plugin-ssr-friendly/-/eslint-plugin-ssr-friendly-1.0.5.tgz", | |
+ "integrity": "sha512-F1vKfzhOnrIXhcx91Y3r1x8vjJAoCex25PUgYErOe6q95T4KuCTz6+LgGQ4TTvhBdCfNqu1U0krAHe3UNuEOqg==", | |
+ "dev": true, | |
+ "dependencies": { | |
+ "globals": "^13.2.0" | |
+ }, | |
+ "peerDependencies": { | |
+ "eslint": ">=0.8.0" | |
+ } | |
+ }, | |
+ "node_modules/eslint-plugin-ssr-friendly/node_modules/globals": { | |
+ "version": "13.12.0", | |
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", | |
+ "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", | |
+ "dev": true, | |
+ "dependencies": { | |
+ "type-fest": "^0.20.2" | |
+ }, | |
+ "engines": { | |
+ "node": ">=8" | |
+ }, | |
+ "funding": { | |
+ "url": "https://github.com/sponsors/sindresorhus" | |
+ } | |
+ }, | |
+ "node_modules/eslint-plugin-ssr-friendly/node_modules/type-fest": { | |
+ "version": "0.20.2", | |
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", | |
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", | |
+ "dev": true, | |
+ "engines": { | |
+ "node": ">=10" | |
+ }, | |
+ "funding": { | |
+ "url": "https://github.com/sponsors/sindresorhus" | |
+ } | |
+ }, | |
"node_modules/eslint-plugin-unicorn": { | |
"version": "37.0.1", | |
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-37.0.1.tgz", | |
@@ -14276,9 +14316,9 @@ | |
} | |
}, | |
"@cspell/cspell-bundled-dicts": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.4.tgz", | |
- "integrity": "sha512-+rbeDNGVX9kYF6ARNLyCRL0lHsS0Kxwb38Dk9bPk/qx3HeKjrVfg6mupFH+kTDWJFCh+ua3D07yPc3TZzcdVIg==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.5.tgz", | |
+ "integrity": "sha512-uuoAYkw1O+AcHx16XN8u42eCm4yLgT0D9vOWnrOKJEScpIvyrgHbL/B71PAkmeTwfhPWhyHb3m/QjYXzio3Olw==", | |
"dev": true, | |
"requires": { | |
"@cspell/dict-ada": "^1.1.2", | |
@@ -14292,7 +14332,7 @@ | |
"@cspell/dict-django": "^1.0.26", | |
"@cspell/dict-dotnet": "^1.0.32", | |
"@cspell/dict-elixir": "^1.0.26", | |
- "@cspell/dict-en_us": "^2.1.2", | |
+ "@cspell/dict-en_us": "^2.1.3", | |
"@cspell/dict-en-gb": "^1.1.33", | |
"@cspell/dict-filetypes": "^2.0.1", | |
"@cspell/dict-fonts": "^1.0.14", | |
@@ -16053,17 +16093,17 @@ | |
"dev": true | |
}, | |
"cspell": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.4.tgz", | |
- "integrity": "sha512-O0jA0Hd6AfBJHLATsQ0QUSDrjcDCUsrWMQSBjqK6EEJKZhZjoBDCKrgJqh8Qp3MvLIgHqq4r75JrsfRk5SZwhQ==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.5.tgz", | |
+ "integrity": "sha512-jfHJ5/TpQ2qrP8K474GoW6axMhkbBx4q2P4TojbkSaDQ/KrvXJjPvvGDYBzCTwu0RyosiLEiJfdyUohGi76eLw==", | |
"dev": true, | |
"requires": { | |
"chalk": "^4.1.2", | |
"commander": "^8.3.0", | |
"comment-json": "^4.1.1", | |
- "cspell-gitignore": "^5.12.4", | |
+ "cspell-gitignore": "^5.12.5", | |
"cspell-glob": "^5.12.4", | |
- "cspell-lib": "^5.12.4", | |
+ "cspell-lib": "^5.12.5", | |
"fast-json-stable-stringify": "^2.1.0", | |
"file-entry-cache": "^6.0.1", | |
"fs-extra": "^10.0.0", | |
@@ -16132,9 +16172,9 @@ | |
} | |
}, | |
"cspell-gitignore": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.4.tgz", | |
- "integrity": "sha512-a5pK6gFEtcGAEESV74m21KvRi0afMw3QE2WXcC0v2lHYyHyHeDK/eLQbk8cVSbuMTaXgDyFtyBwSP7Qq0PAnFg==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.5.tgz", | |
+ "integrity": "sha512-I1QizO6LSSpeaEzBjtmcPu09l7bMvvUsVhsHWtzp6RVz3DXQq/ntn/s5HPGCcRVTXO9eeRePTy1LfOsHZO1cMQ==", | |
"dev": true, | |
"requires": { | |
"cspell-glob": "^5.12.4", | |
@@ -16157,12 +16197,12 @@ | |
"dev": true | |
}, | |
"cspell-lib": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.4.tgz", | |
- "integrity": "sha512-NqmQ1j5PsQZJxUqdPaEMrNSKmIiaWSQVzITGfW08FEiTCqSpHxRQdNMM6B7nYUS0NgS5wYwycNMkEWaRQebI+Q==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.5.tgz", | |
+ "integrity": "sha512-7pPFWrojoeQnYchFKLBpeF+39ZKIyLuuneydZCaOIFGzUwyKX6uK4Cfz9rEs0CBLqXqlsectm9WOloW3KTs8KA==", | |
"dev": true, | |
"requires": { | |
- "@cspell/cspell-bundled-dicts": "^5.12.4", | |
+ "@cspell/cspell-bundled-dicts": "^5.12.5", | |
"@cspell/cspell-types": "^5.12.4", | |
"clear-module": "^4.1.1", | |
"comment-json": "^4.1.1", | |
@@ -16170,7 +16210,7 @@ | |
"cosmiconfig": "^7.0.1", | |
"cspell-glob": "^5.12.4", | |
"cspell-io": "^5.12.4", | |
- "cspell-trie-lib": "^5.12.4", | |
+ "cspell-trie-lib": "^5.12.5", | |
"find-up": "^5.0.0", | |
"fs-extra": "^10.0.0", | |
"gensequence": "^3.1.1", | |
@@ -16181,9 +16221,9 @@ | |
} | |
}, | |
"cspell-trie-lib": { | |
- "version": "5.12.4", | |
- "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.4.tgz", | |
- "integrity": "sha512-WXnqSVyqP7ZhRWxF3C4olXATETyxD+43f0T0Jzlq0Dz8nxXmzEl79Ws9sEZo4ssLTMXaEcx4Uh361vQYZY+irA==", | |
+ "version": "5.12.5", | |
+ "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.5.tgz", | |
+ "integrity": "sha512-oF2LR860BhKISIyQ8FSzq7a+dB9fbFcYP42LeO8NsXk0qhv9gTR3ReiyA1rcp9ocClpg26AhU08dNuAxcHQBmA==", | |
"dev": true, | |
"requires": { | |
"fs-extra": "^10.0.0", | |
@@ -17037,6 +17077,32 @@ | |
} | |
} | |
}, | |
+ "eslint-plugin-ssr-friendly": { | |
+ "version": "1.0.5", | |
+ "resolved": "https://registry.npmjs.org/eslint-plugin-ssr-friendly/-/eslint-plugin-ssr-friendly-1.0.5.tgz", | |
+ "integrity": "sha512-F1vKfzhOnrIXhcx91Y3r1x8vjJAoCex25PUgYErOe6q95T4KuCTz6+LgGQ4TTvhBdCfNqu1U0krAHe3UNuEOqg==", | |
+ "dev": true, | |
+ "requires": { | |
+ "globals": "^13.2.0" | |
+ }, | |
+ "dependencies": { | |
+ "globals": { | |
+ "version": "13.12.0", | |
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", | |
+ "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", | |
+ "dev": true, | |
+ "requires": { | |
+ "type-fest": "^0.20.2" | |
+ } | |
+ }, | |
+ "type-fest": { | |
+ "version": "0.20.2", | |
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", | |
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", | |
+ "dev": true | |
+ } | |
+ } | |
+ }, | |
"eslint-plugin-unicorn": { | |
"version": "37.0.1", | |
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-37.0.1.tgz", |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment