Rob Colbert
2 years ago
11 changed files with 822 additions and 0 deletions
@ -0,0 +1 @@ |
|||
node_modules |
@ -0,0 +1,25 @@ |
|||
{ |
|||
"bitwise": true, |
|||
"browser": true, |
|||
"curly": true, |
|||
"eqeqeq": true, |
|||
"latedef": true, |
|||
"noarg": true, |
|||
"node": true, |
|||
"strict": "global", |
|||
"undef": true, |
|||
"unused": true, |
|||
"futurehostile": true, |
|||
"esversion": 9, |
|||
"mocha": true, |
|||
"globals": { |
|||
"markdown": true, |
|||
"moment": true, |
|||
"numeral": true, |
|||
"io": true, |
|||
"Chart": true, |
|||
"CodeMirror": true, |
|||
"UIkit": true, |
|||
"twttr": true |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
# DTP Nice Game SDK |
|||
|
|||
The Nice Game SDK is a lightweight HTML5 gaming engine that renders to <canvas> and supports the Web Audio API, media streaming, and an abstract input manager to help make the creation of mini-games, casual games, and playable memes as quick and simple as possible. |
|||
|
|||
## Installing |
|||
|
|||
```sh |
|||
yarn add https://git.digitaltelepresence.com/digital-telepresence/dtp-nice-game.git |
|||
|
|||
app.use('/dtp-nice-game', express.static(path.join(__dirname, 'node_modules', 'dtp-nice-game', 'dist'))); |
|||
|
|||
import { NiceGame } from '/dtp-nice-game/nice-game.js'; |
|||
``` |
|||
|
|||
## NiceGame |
|||
|
|||
## NiceInput |
|||
|
|||
## NiceAudio |
|||
|
|||
## NiceSprite |
|||
|
|||
## NiceImage |
|||
|
|||
## NiceLog |
@ -0,0 +1,139 @@ |
|||
// lib/nice-audio.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
const DTP_COMPONENT_NAME = 'nice-audio'; |
|||
|
|||
import NiceLog from './nice-log.js'; |
|||
|
|||
const AudioContext = window.AudioContext || window.webkitAudioContext; |
|||
|
|||
/** |
|||
* NiceAudio is the audio engine for the Nice Arcade SDK. It can load audio |
|||
* files into audio buffers, and play the buffers. It can also stream larger |
|||
* audio files (ex: background music). |
|||
*/ |
|||
export default class NiceAudio { |
|||
|
|||
constructor ( ) { |
|||
this.log = new NiceLog(DTP_COMPONENT_NAME); |
|||
} |
|||
|
|||
start ( ) { |
|||
this.ctx = new AudioContext(); |
|||
this.masterVolume = this.ctx.createGain(); |
|||
this.masterVolume.connect(this.ctx.destination); |
|||
|
|||
this.musicGain = this.ctx.createGain(); |
|||
this.musicGain.value = 0.7; |
|||
this.musicGain.connect(this.masterVolume); |
|||
} |
|||
|
|||
/** |
|||
* Loads an audio resource from a specified URL, decodes that audio data into |
|||
* an Audio Buffer, and resolves the buffer. This is commonly used for small |
|||
* audio files to be used as sound effects. Music, multi-megabyte, and multi- |
|||
* minute audio should be streamed, not loaded into memory. |
|||
* @param {URL} url The audio resource to be loaded into an in-memory audio buffer. |
|||
* @returns Promise that resolves the audio buffer or rejects with an error. |
|||
*/ |
|||
loadAudioBuffer (url) { |
|||
return new Promise(async (resolve, reject) => { |
|||
const response = await fetch(url); |
|||
const audioData = await response.arrayBuffer(); |
|||
this.ctx.decodeAudioData(audioData, resolve, reject); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Creates a buffer source object, sets the specified buffer as the data |
|||
* source, creates a gain node, configures both as specified, plus the buffer |
|||
* source into the gain node, plugs the gain node into masterVolume. |
|||
* |
|||
* If you hold onto the `source` or `gain` objects returned, you may create a |
|||
* memory leak and/or overwhelm audio resources on the player's device. |
|||
* |
|||
* @param {AudioBuffer} buffer |
|||
* @param {Object} options Allows specification of `volume` (default: 1.0) and `loop` (default: false). |
|||
* @returns An object containing a `source` and `gain` object that can be used for additional routing, effects, etc. |
|||
*/ |
|||
playAudioBuffer (buffer, options = { }) { |
|||
options = Object.assign({ |
|||
volume: 1.0, |
|||
loop: false, |
|||
}, options); |
|||
|
|||
const source = this.ctx.createBufferSource(); |
|||
source.buffer = buffer; |
|||
source.loop = options.loop; |
|||
|
|||
const gain = this.ctx.createGain(); |
|||
gain.value = options.volume; |
|||
|
|||
source.connect(gain); |
|||
gain.connect(this.masterVolume); |
|||
|
|||
source.start(); |
|||
|
|||
return { gain, source }; |
|||
} |
|||
|
|||
/** |
|||
* Will stop any current playing music, destroy the current audio source and |
|||
* Audio element, then create a new stack to support the new resource. |
|||
* @param {URL} url The URL of the resource to be set as the new music stream |
|||
* for the audio engine. |
|||
*/ |
|||
setMusicStream (url) { |
|||
this.stopMusicStream(); |
|||
this.log.debug('setMusicStream', 'setting new music stream', { url }); |
|||
this.music = new Audio(url); |
|||
} |
|||
|
|||
playMusicStream ( ) { |
|||
if (this.musicSource) { |
|||
return; |
|||
} |
|||
|
|||
this.musicSource = this.ctx.createMediaElementSource(this.music); |
|||
this.musicSource.connect(this.musicGain); |
|||
|
|||
this.log.debug('playMusicStream', 'starting music stream playback'); |
|||
this.music.play(); |
|||
} |
|||
|
|||
stopMusicStream ( ) { |
|||
if (!this.musicSource) { |
|||
return; |
|||
} |
|||
|
|||
this.log.debug('pauseMusicStream', 'stopping music stream playback'); |
|||
this.music.pause(); |
|||
|
|||
this.musicGain.value = 0; |
|||
|
|||
this.musicSource.disconnect(this.musicGain); |
|||
delete this.musicSource; |
|||
} |
|||
|
|||
get musicVolume ( ) { return this.musicGain.value; } |
|||
set musicVolume (volume) { |
|||
this.musicGain.value = volume; |
|||
} |
|||
|
|||
get haveMusicStream ( ) { |
|||
return !!this.music && |
|||
!!this.musicSource && |
|||
!!this.musicGain |
|||
; |
|||
} |
|||
|
|||
get isMusicPaused ( ) { |
|||
if (!this.music) { |
|||
return true; |
|||
} |
|||
return this.music.paused; |
|||
} |
|||
} |
@ -0,0 +1,70 @@ |
|||
// lib/nice-game.js
|
|||
// Copyright (C) 2022 Rob Colbert
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
import NiceLog from '/dist/js/lib/nice-log.js'; |
|||
import NiceAudio from '/dist/js/lib/nice-audio.js'; |
|||
import NiceImage from './nice-image.js'; |
|||
import NiceSprite from './nice-sprite.js'; |
|||
|
|||
import { |
|||
NiceInputTools, |
|||
NiceInputButton, |
|||
NiceInputKey, |
|||
NiceInput, |
|||
} from '/dist/js/lib/nice-input.js'; |
|||
|
|||
class NiceGame { |
|||
|
|||
constructor (componentName) { |
|||
this.componentName = componentName; |
|||
|
|||
this.log = new NiceLog(this.componentName); |
|||
this.log.enable(true); |
|||
|
|||
this.sprites = { }; |
|||
this.eggs = [ ]; |
|||
} |
|||
|
|||
async startGameEngine (onGameUpdate) { |
|||
this.gameDisplayCanvas = document.getElementById('game-display'); |
|||
if (!this.gameDisplayCanvas) { |
|||
this.log.error('startup', 'failed to find game display canvas'); |
|||
throw new Error('failed to find game display canvas'); |
|||
} |
|||
|
|||
this.onGameUpdate = onGameUpdate; |
|||
|
|||
this.input = new NiceInput(); |
|||
this.audio = new NiceAudio(); |
|||
|
|||
this.log.info('startup', 'starting game update loop'); |
|||
this.gameDisplayCanvas.width = 960; |
|||
this.gameDisplayCanvas.height = 540; |
|||
|
|||
this.gameDisplayCtx = this.gameDisplayCanvas.getContext('2d'); |
|||
this.onUpdateDisplay = this.updateDisplay.bind(this); |
|||
window.requestAnimationFrame(this.onUpdateDisplay); |
|||
} |
|||
|
|||
updateDisplay ( ) { |
|||
if (this.onGameUpdate && (typeof this.onGameUpdate === 'function')) { |
|||
this.onGameUpdate(this.gameDisplayCtx); |
|||
} |
|||
window.requestAnimationFrame(this.onUpdateDisplay); |
|||
} |
|||
} |
|||
|
|||
export { |
|||
NiceAudio, |
|||
NiceGame, |
|||
NiceImage, |
|||
NiceInputButton, |
|||
NiceInputKey, |
|||
NiceInputTools, |
|||
NiceInput, |
|||
NiceLog, |
|||
NiceSprite, |
|||
}; |
@ -0,0 +1,25 @@ |
|||
// lib/nice-image.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
export default class NiceImage { |
|||
|
|||
async load (url, width, height) { |
|||
this.image = new Image(width, height); |
|||
return new Promise((resolve, reject) => { |
|||
this.image.onload = ( ) => resolve(this); |
|||
this.image.onerror = reject; |
|||
this.image.src = url; |
|||
}); |
|||
} |
|||
|
|||
get width ( ) { return this.image.width; } |
|||
get height ( ) { return this.image.height; } |
|||
|
|||
draw (ctx, x, y) { |
|||
if (!this.image) { return; } |
|||
ctx.drawImage(this.image, x, y); |
|||
} |
|||
} |
@ -0,0 +1,163 @@ |
|||
// lib/nice-input.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
const DTP_COMPONENT_NAME = 'nice-input'; |
|||
|
|||
import NiceLog from './nice-log.js'; |
|||
|
|||
/** |
|||
* Static support methods used across the variety of Input classes. |
|||
*/ |
|||
export class NiceInputTools { |
|||
|
|||
/** |
|||
* Entirely cancels and stops all default behavior on the given event. This is |
|||
* useful for disabling long-press actions on buttons in a game that expects |
|||
* the player to hold a button down to move in a direction. |
|||
* |
|||
* @param {Event} event The DOM input event to be canceled like as if Reddit |
|||
* got involved. |
|||
*/ |
|||
static cancelEvent (event) { |
|||
event = event || window.event; |
|||
event.preventDefault(); |
|||
event.stopPropagation(); |
|||
event.cancelBubble = true; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* The NiceInputButton class implements the glue between the Nice engine and the |
|||
* browser's various methods and events for working with a button. |
|||
*/ |
|||
export class NiceInputButton { |
|||
|
|||
constructor (manager, actionName, buttonId) { |
|||
this.manager = manager; |
|||
this.log = manager.log; |
|||
|
|||
this.actionName = actionName; |
|||
this.isPressed = false; |
|||
|
|||
this.element = document.getElementById(buttonId); |
|||
if (!this.element) { |
|||
throw new Error(`button element ${buttonId} does not exist in view`); |
|||
} |
|||
|
|||
this.log.debug('NiceInputButton', 'registering event callbacks', { element: this.element }); |
|||
|
|||
/* |
|||
* Events that mean a button is currently "down" |
|||
*/ |
|||
this.element.addEventListener('touchstart', this.onInputStart.bind(this)); |
|||
this.element.addEventListener('mousedown', this.onInputStart.bind(this)); |
|||
|
|||
/* |
|||
* Events that mean a button is no longer "down" |
|||
*/ |
|||
this.element.addEventListener('touchend', this.onInputEnd.bind(this)); |
|||
this.element.addEventListener('touchcancel', this.onInputEnd.bind(this)); |
|||
this.element.addEventListener('mouseup', this.onInputEnd.bind(this)); |
|||
this.element.addEventListener('mouseleave', this.onInputEnd.bind(this)); |
|||
|
|||
/* |
|||
* Ignored, but also needs to be canceled |
|||
*/ |
|||
this.element.addEventListener('touchmove', NiceInputTools.cancelEvent); |
|||
} |
|||
|
|||
async onInputStart (event) { |
|||
NiceInputTools.cancelEvent(event); |
|||
this.log.debug('onInputStart', 'button down', { action: this.actionName }); |
|||
this.element.classList.add('active'); |
|||
this.isPressed = true; |
|||
} |
|||
|
|||
async onInputEnd (event) { |
|||
NiceInputTools.cancelEvent(event); |
|||
this.log.debug('onInputEnd', 'button up', { action: this.actionName }); |
|||
this.element.classList.remove('active'); |
|||
this.isPressed = false; |
|||
} |
|||
} |
|||
|
|||
export class NiceInputKey { |
|||
|
|||
constructor (actionName, keyCode) { |
|||
this.actionName = actionName; |
|||
this.keyCode = keyCode; |
|||
this.isPressed = false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* The NiceInput class manages interaction with the user through the browser and |
|||
* DOM events. You don't have to worry about those. You simply add an input by |
|||
* name, specify the ID of the control in the HTML View, and NiceInput will |
|||
* handle all interaction with that control. |
|||
* |
|||
* The game programmer can then check the state of their inputs during normal |
|||
* game logic using one consistent interface: NiceInput. |
|||
*/ |
|||
export class NiceInput { |
|||
|
|||
constructor ( ) { |
|||
this.log = new NiceLog(DTP_COMPONENT_NAME); |
|||
this.log.enable(true); |
|||
|
|||
this.buttons = { }; |
|||
this.keys = { }; |
|||
|
|||
document.addEventListener('keydown', this.onKeyDown.bind(this)); |
|||
document.addEventListener('keyup', this.onKeyUp.bind(this)); |
|||
} |
|||
|
|||
addButton (actionName, buttonId) { |
|||
const button = new NiceInputButton(this, actionName, buttonId); |
|||
this.buttons[actionName] = button; |
|||
} |
|||
|
|||
addKey (actionName, keyCode) { |
|||
const key = new NiceInputKey (actionName, keyCode); |
|||
this.keys[actionName] = key; |
|||
} |
|||
|
|||
async onKeyDown (event) { |
|||
this.log.debug('onKeyDown', 'key pressed', { event }); |
|||
|
|||
const actionName = Object |
|||
.keys(this.keys) |
|||
.find((key) => this.keys[key].keyCode === event.code) |
|||
; |
|||
if (!actionName) { return; } |
|||
|
|||
const key = this.keys[actionName]; |
|||
key.isPressed = true; |
|||
|
|||
const button = this.buttons[actionName]; |
|||
if (button) { |
|||
button.element.classList.add('active'); |
|||
} |
|||
} |
|||
|
|||
async onKeyUp (event) { |
|||
this.log.debug('onKeyUp', 'key released', { event }); |
|||
|
|||
const actionName = Object |
|||
.keys(this.keys) |
|||
.find((key) => this.keys[key].keyCode === event.code) |
|||
; |
|||
if (!actionName) { return; } |
|||
|
|||
const key = this.keys[actionName]; |
|||
key.isPressed = false; |
|||
|
|||
const button = this.buttons[actionName]; |
|||
if (button) { |
|||
button.element.classList.remove('active'); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,125 @@ |
|||
// lib/nice-log.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
export default class NiceLog { |
|||
|
|||
constructor (componentName, options) { |
|||
this.componentName = componentName; |
|||
this.options = Object.assign({ |
|||
color: { |
|||
debug: '#808080', |
|||
info: '#249324', |
|||
warn: '#AC7C37', |
|||
error: '#A74949', |
|||
}, |
|||
size: { |
|||
label: 120, |
|||
}, |
|||
}, options); |
|||
|
|||
this.css = { |
|||
debug: { |
|||
label: ` |
|||
display: inline-block; |
|||
background-color: ${this.options.color.debug}; |
|||
color: white; |
|||
width: ${this.options.size.label}px; |
|||
padding: 2px 4px; |
|||
border-radius: 4px; |
|||
`,
|
|||
message: ` |
|||
color: ${this.options.color.debug}; |
|||
`,
|
|||
}, |
|||
info: { |
|||
label: ` |
|||
background-color: ${this.options.color.info}; |
|||
color: white; |
|||
width: ${this.options.size.label}px; |
|||
padding: 2px 4px; |
|||
border-radius: 4px; |
|||
`,
|
|||
message: ` |
|||
color: ${this.options.color.info}; |
|||
`,
|
|||
}, |
|||
warn: { |
|||
label: ` |
|||
background-color: ${this.options.color.warn}; |
|||
color: white; |
|||
width: ${this.options.size.label}px; |
|||
padding: 2px 4px; |
|||
border-radius: 4px; |
|||
`,
|
|||
message: ` |
|||
color: ${this.options.color.warn}; |
|||
`,
|
|||
}, |
|||
error: { |
|||
label: ` |
|||
background-color: ${this.options.color.error}; |
|||
color: white; |
|||
width: ${this.options.size.label}px; |
|||
padding: 2px 4px; |
|||
border-radius: 4px; |
|||
`,
|
|||
message: ` |
|||
color: ${this.options.color.error}; |
|||
`,
|
|||
}, |
|||
}; |
|||
|
|||
const env = document.querySelector('body').getAttribute('data-dtp-env'); |
|||
if (env === 'local') { |
|||
this.enable(); |
|||
} |
|||
} |
|||
|
|||
enable (enabled = true) { |
|||
this.enabled = enabled; |
|||
} |
|||
|
|||
debug (event, msg, data) { |
|||
this.write('debug', this.css.debug, event, msg, data); |
|||
} |
|||
|
|||
log (event, msg, data) { this.info(event, msg, data); } |
|||
|
|||
info (event, msg, data) { |
|||
this.write('log', this.css.info, event, msg, data); |
|||
} |
|||
|
|||
warn (event, msg, data) { // alias for warning
|
|||
this.warning(event, msg, data); |
|||
} |
|||
|
|||
warning (event, msg, data) { |
|||
this.write('warn', this.css.warn, event, msg, data); |
|||
} |
|||
|
|||
error (event, msg, data) { |
|||
this.write('error', this.css.error, event, msg, data); |
|||
if (data && data.error) { |
|||
console.error(data.error); |
|||
} |
|||
} |
|||
|
|||
write (method, css, event, msg, data) { |
|||
if (!this.enabled) { return; } |
|||
if (data) { |
|||
console[method]('%c%s%c: %s', |
|||
css.label, `${this.componentName}.${event}`, |
|||
css.message, msg, |
|||
data, |
|||
); |
|||
} else { |
|||
console[method]('%c%s%c: %s', |
|||
css.label, `${this.componentName}.${event}`, |
|||
css.message, msg, |
|||
); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,27 @@ |
|||
// lib/nice-sprite.js
|
|||
// Copyright (C) 2022 Rob Colbert @[email protected]
|
|||
// License: Apache-2.0
|
|||
|
|||
'use strict'; |
|||
|
|||
import NiceImage from './nice-image.js'; |
|||
|
|||
export default class NiceSprite { |
|||
|
|||
constructor ( ) { |
|||
this.position = { x: 0, y: 0 }; |
|||
} |
|||
|
|||
async load (url, width, height) { |
|||
this.image = new NiceImage(); |
|||
return this.image.load(url, width, height); |
|||
} |
|||
|
|||
render (ctx) { |
|||
this.image.draw( |
|||
ctx, |
|||
this.position.x - (this.image.width / 2), |
|||
this.position.y - (this.image.height / 2), |
|||
); |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"name": "dtp-nice-game", |
|||
"version": "0.1.0", |
|||
"description": "DTP Nice Game SDK", |
|||
"main": "./lib/nice-game.js", |
|||
"repository": "https://git.digitaltelepresence.com/digital-telepresence/dtp-nice-game.git", |
|||
"author": "DTP Technologies, LLC", |
|||
"license": "Apache-2.0", |
|||
"private": false, |
|||
"dependencies": { |
|||
"jshint": "^2.13.4" |
|||
} |
|||
} |
@ -0,0 +1,209 @@ |
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. |
|||
# yarn lockfile v1 |
|||
|
|||
|
|||
balanced-match@^1.0.0: |
|||
version "1.0.2" |
|||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" |
|||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== |
|||
|
|||
brace-expansion@^1.1.7: |
|||
version "1.1.11" |
|||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" |
|||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== |
|||
dependencies: |
|||
balanced-match "^1.0.0" |
|||
concat-map "0.0.1" |
|||
|
|||
cli@~1.0.0: |
|||
version "1.0.1" |
|||
resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" |
|||
integrity sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ= |
|||
dependencies: |
|||
exit "0.1.2" |
|||
glob "^7.1.1" |
|||
|
|||
[email protected]: |
|||
version "0.0.1" |
|||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" |
|||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= |
|||
|
|||
[email protected]: |
|||
version "1.1.0" |
|||
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" |
|||
integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= |
|||
dependencies: |
|||
date-now "^0.1.4" |
|||
|
|||
core-util-is@~1.0.0: |
|||
version "1.0.3" |
|||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" |
|||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== |
|||
|
|||
date-now@^0.1.4: |
|||
version "0.1.4" |
|||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" |
|||
integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= |
|||
|
|||
dom-serializer@0: |
|||
version "0.2.2" |
|||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" |
|||
integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== |
|||
dependencies: |
|||
domelementtype "^2.0.1" |
|||
entities "^2.0.0" |
|||
|
|||
domelementtype@1: |
|||
version "1.3.1" |
|||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" |
|||
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== |
|||
|
|||
domelementtype@^2.0.1: |
|||
version "2.2.0" |
|||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" |
|||
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== |
|||
|
|||
[email protected]: |
|||
version "2.3.0" |
|||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" |
|||
integrity sha1-LeWaCCLVAn+r/28DLCsloqir5zg= |
|||
dependencies: |
|||
domelementtype "1" |
|||
|
|||
[email protected]: |
|||
version "1.5.1" |
|||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" |
|||
integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= |
|||
dependencies: |
|||
dom-serializer "0" |
|||
domelementtype "1" |
|||
|
|||
[email protected]: |
|||
version "1.0.0" |
|||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" |
|||
integrity sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY= |
|||
|
|||
entities@^2.0.0: |
|||
version "2.2.0" |
|||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" |
|||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== |
|||
|
|||
[email protected], [email protected]: |
|||
version "0.1.2" |
|||
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" |
|||
integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= |
|||
|
|||
fs.realpath@^1.0.0: |
|||
version "1.0.0" |
|||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" |
|||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= |
|||
|
|||
glob@^7.1.1: |
|||
version "7.2.0" |
|||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" |
|||
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== |
|||
dependencies: |
|||
fs.realpath "^1.0.0" |
|||
inflight "^1.0.4" |
|||
inherits "2" |
|||
minimatch "^3.0.4" |
|||
once "^1.3.0" |
|||
path-is-absolute "^1.0.0" |
|||
|
|||
[email protected]: |
|||
version "3.8.3" |
|||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" |
|||
integrity sha1-mWwosZFRaovoZQGn15dX5ccMEGg= |
|||
dependencies: |
|||
domelementtype "1" |
|||
domhandler "2.3" |
|||
domutils "1.5" |
|||
entities "1.0" |
|||
readable-stream "1.1" |
|||
|
|||
inflight@^1.0.4: |
|||
version "1.0.6" |
|||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" |
|||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= |
|||
dependencies: |
|||
once "^1.3.0" |
|||
wrappy "1" |
|||
|
|||
inherits@2, inherits@~2.0.1: |
|||
version "2.0.4" |
|||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" |
|||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== |
|||
|
|||
[email protected]: |
|||
version "0.0.1" |
|||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" |
|||
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= |
|||
|
|||
jshint@^2.13.4: |
|||
version "2.13.4" |
|||
resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.13.4.tgz#cee025a57c3f393d5455532d9ec7ccb018f890db" |
|||
integrity sha512-HO3bosL84b2qWqI0q+kpT/OpRJwo0R4ivgmxaO848+bo10rc50SkPnrtwSFXttW0ym4np8jbJvLwk5NziB7jIw== |
|||
dependencies: |
|||
cli "~1.0.0" |
|||
console-browserify "1.1.x" |
|||
exit "0.1.x" |
|||
htmlparser2 "3.8.x" |
|||
lodash "~4.17.21" |
|||
minimatch "~3.0.2" |
|||
strip-json-comments "1.0.x" |
|||
|
|||
lodash@~4.17.21: |
|||
version "4.17.21" |
|||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" |
|||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== |
|||
|
|||
minimatch@^3.0.4: |
|||
version "3.1.2" |
|||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" |
|||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== |
|||
dependencies: |
|||
brace-expansion "^1.1.7" |
|||
|
|||
minimatch@~3.0.2: |
|||
version "3.0.8" |
|||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" |
|||
integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== |
|||
dependencies: |
|||
brace-expansion "^1.1.7" |
|||
|
|||
once@^1.3.0: |
|||
version "1.4.0" |
|||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" |
|||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= |
|||
dependencies: |
|||
wrappy "1" |
|||
|
|||
path-is-absolute@^1.0.0: |
|||
version "1.0.1" |
|||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" |
|||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= |
|||
|
|||
[email protected]: |
|||
version "1.1.13" |
|||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" |
|||
integrity sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4= |
|||
dependencies: |
|||
core-util-is "~1.0.0" |
|||
inherits "~2.0.1" |
|||
isarray "0.0.1" |
|||
string_decoder "~0.10.x" |
|||
|
|||
string_decoder@~0.10.x: |
|||
version "0.10.31" |
|||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" |
|||
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= |
|||
|
|||
[email protected]: |
|||
version "1.0.4" |
|||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" |
|||
integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E= |
|||
|
|||
wrappy@1: |
|||
version "1.0.2" |
|||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" |
|||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= |
Loading…
Reference in new issue