Browse Source

created

develop
Rob Colbert 2 years ago
parent
commit
7fd13fcf91
  1. 1
      .gitignore
  2. 25
      .jshintrc
  3. 25
      README.md
  4. 139
      lib/nice-audio.js
  5. 70
      lib/nice-game.js
  6. 25
      lib/nice-image.js
  7. 163
      lib/nice-input.js
  8. 125
      lib/nice-log.js
  9. 27
      lib/nice-sprite.js
  10. 13
      package.json
  11. 209
      yarn.lock

1
.gitignore

@ -0,0 +1 @@
node_modules

25
.jshintrc

@ -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
}
}

25
README.md

@ -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

139
lib/nice-audio.js

@ -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;
}
}

70
lib/nice-game.js

@ -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,
};

25
lib/nice-image.js

@ -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);
}
}

163
lib/nice-input.js

@ -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');
}
}
}

125
lib/nice-log.js

@ -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,
);
}
}
}

27
lib/nice-sprite.js

@ -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),
);
}
}

13
package.json

@ -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"
}
}

209
yarn.lock

@ -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…
Cancel
Save