@code-dot-org/dance-party
Advanced tools
Comparing version 0.0.27 to 0.0.28
{ | ||
"name": "@code-dot-org/dance-party", | ||
"version": "0.0.27", | ||
"version": "0.0.28", | ||
"description": "", | ||
@@ -9,7 +9,7 @@ "main": "dist/main.js", | ||
"dev": "webpack-dev-server --mode development", | ||
"codecov": "mkdir coverage && nyc report --reporter=text-lcov > ./coverage/unit.lcov && codecov", | ||
"codecov": "mkdir -p coverage && nyc report --reporter=text-lcov > ./coverage/unit.lcov && codecov", | ||
"lint": "eslint --ext .js src test", | ||
"test": "npm run lint && nyc tape ./test/**/*.js", | ||
"test": "npm run lint && nyc npm run test:unit && npm run test:integration", | ||
"test:unit": "tape ./test/unit/*.js", | ||
"test:integration": "tape ./test/integration/*.js", | ||
"test:integration": "karma start", | ||
"preversion": "npm run test", | ||
@@ -26,3 +26,3 @@ "version": "npm run build", | ||
"devDependencies": { | ||
"@code-dot-org/p5.play": "1.3.5-cdo", | ||
"@code-dot-org/p5.play": "1.3.8-cdo", | ||
"babel-core": "^6.26.3", | ||
@@ -36,3 +36,11 @@ "babel-loader": "^7.1.4", | ||
"eslint": "^2.8.0", | ||
"istanbul-instrumenter-loader": "^3.0.1", | ||
"jsdom": "^12.2.0", | ||
"karma": "^2.0.5", | ||
"karma-chrome-launcher": "^2.2.0", | ||
"karma-coverage": "^1.1.2", | ||
"karma-sourcemap-loader": "^0.3.7", | ||
"karma-tap": "^4.1.4", | ||
"karma-tap-pretty-reporter": "^4.1.0", | ||
"karma-webpack": "4.0.0-rc.2", | ||
"nyc": "^13.1.0", | ||
@@ -39,0 +47,0 @@ "raw-loader": "^0.5.1", |
@@ -24,3 +24,10 @@ module.exports = { | ||
{name: "XHighKick", mirror: false, shortBurst: true}, | ||
{name: "XBend", mirror: false, shortBurst: true}, | ||
{name: "XFever", mirror: false, shortBurst: true}, | ||
{name: "XHop", mirror: false, shortBurst: true}, | ||
{name: "XKnee", mirror: false, shortBurst: true}, | ||
{name: "XKneel", mirror: false, shortBurst: true}, | ||
{name: "XOle", mirror: false, shortBurst: true}, | ||
{name: "XSlide", mirror: false, shortBurst: true}, | ||
], | ||
}; |
@@ -18,5 +18,24 @@ /* eslint-disable */ | ||
ThisOrThat: 10, | ||
Thriller: 11 | ||
Thriller: 11, | ||
XArmsSide: 12, | ||
XArmsUp: 13, | ||
XJump: 14, | ||
XClapSide: 15, | ||
XHeadHips: 16, | ||
XHighKick: 17, | ||
XBend: 18, | ||
XFever: 19, | ||
XHop: 20, | ||
XKnee: 21, | ||
XKneel: 22, | ||
XOle: 23, | ||
XSlide: 24, | ||
}; | ||
var QueueType = { | ||
every: 'every', | ||
after: 'after', | ||
other: 'other' | ||
}; | ||
// Event handlers, loops, and callbacks. | ||
@@ -34,2 +53,5 @@ var inputEvents = []; | ||
/** | ||
* @returns {Object} An object with two arrays, each of which is a list of numbers | ||
*/ | ||
function getCueList() { | ||
@@ -61,21 +83,53 @@ var timestamps = []; | ||
/** | ||
* @param {Object} events - An object where each key is an event type. Each value | ||
* is another object, where the keys represent the param of the event to be run | ||
*/ | ||
function runUserEvents(events) { | ||
var currentEvents = {}; | ||
// We have three separate event queues. | ||
// First we run every N seconds/measures events | ||
// Then we run after N seconds/measures events | ||
// Finally we run all other events | ||
var queues = {}; | ||
Object.keys(QueueType).forEach(function(key) { | ||
queues[key] = []; | ||
}); | ||
// Iterate through all of the inputEvents we've cached in the interpreter, looking | ||
// to see if they meet the criteria of the passed in events object. If they do, | ||
// we add them to the appropriate event queue | ||
for (var i = 0; i < inputEvents.length; i++) { | ||
var eventType = inputEvents[i].type; | ||
var event = inputEvents[i].event; | ||
var param = inputEvents[i].param; | ||
var priority = inputEvents[i].priority; | ||
var queueType = inputEvents[i].queueType; | ||
if (events[eventType] && events[eventType][param]) { | ||
//If there are multiple cues of the same type, only run the event with the highest priority | ||
if (!currentEvents[eventType] || currentEvents[eventType].priority < priority) { | ||
currentEvents[eventType] = {event: event, priority: priority}; | ||
if (!queues[queueType]) { | ||
throw new Error('Unknown queueType: ', queueType); | ||
} | ||
queues[queueType].push({ | ||
priority: inputEvents[i].priority, | ||
func: inputEvents[i].func | ||
}); | ||
} | ||
} | ||
for (var input in currentEvents){ | ||
if(currentEvents.hasOwnProperty(input)){ | ||
currentEvents[input].event(); | ||
} | ||
function prioritySort(a, b) { | ||
// TODO: If compareFunction(a, b) returns 0, leave a and b unchanged with respect | ||
// to each other, but sorted with respect to all different elements. Note: the | ||
// ECMAscript standard does not guarantee this behaviour, and thus not all | ||
// browsers (e.g. Mozilla versions dating back to at least 2003) respect this. | ||
// ^ Matters to us, because we initially seed items according to block position | ||
// and we want to maintain that ordering in our sort when priorities are equal | ||
// There are ways we could ensure that | ||
return a.priority - b.priority; | ||
} | ||
function executeFuncs(item) { | ||
item.func(); | ||
} | ||
queues[QueueType.every].sort(prioritySort).forEach(executeFuncs); | ||
queues[QueueType.after].sort(prioritySort).forEach(executeFuncs); | ||
queues[QueueType.other].forEach(executeFuncs); | ||
} | ||
@@ -99,19 +153,36 @@ | ||
function whenKey(key, event) { | ||
/** | ||
* @param {string} key - Many options, including up, down, left, right, a-z, 0-9 | ||
* @param {function} func - Code to run when event fires | ||
*/ | ||
function whenKey(key, func) { | ||
inputEvents.push({ | ||
type: 'this.p5_.keyWentDown', | ||
event: event, | ||
param: key | ||
func: func, | ||
param: key, | ||
queueType: QueueType.other, | ||
}); | ||
} | ||
function whenPeak(range, event) { | ||
/** | ||
* @param {string} range - Should be "bass", "mid", or "treble" | ||
* @param {function} func - Code to run when event fires | ||
*/ | ||
function whenPeak(range, func) { | ||
inputEvents.push({ | ||
type: 'Dance.fft.isPeak', | ||
event: event, | ||
param: range | ||
func: func, | ||
param: range, | ||
queueType: QueueType.other, | ||
}); | ||
} | ||
function atTimestamp(timestamp, unit, event) { | ||
/** | ||
* @param {number} timestamp | ||
* @param {string} unit - Should be "measures" or "seconds" | ||
* @param {function} func - Code to run when event fires | ||
*/ | ||
function atTimestamp(timestamp, unit, func) { | ||
// Despite the functions name, if we call atTimestamp(4, "measures", foo), we | ||
// actually want to fire on the 5th measure (i.e after 4 measures have completed) | ||
if (unit === "measures") { | ||
@@ -121,13 +192,18 @@ timestamp += 1; | ||
// Increment priority by 1 to account for 'atTimestamp' events having a higher priority | ||
// than everySecond events when they have share a timestamp parameter | ||
inputEvents.push({ | ||
type: 'cue-' + unit, | ||
event: event, | ||
func: func, | ||
param: timestamp, | ||
priority: timestamp + 1 | ||
queueType: QueueType.after, | ||
// actual priority value is inconsequential here | ||
priority: 0, | ||
}); | ||
} | ||
function everySeconds(n, unit, event) { | ||
/** | ||
* @param {number} n | ||
* @param {string} unit - Should be "measures" or "seconds" | ||
* @param {function} func - Code to run when event fires | ||
*/ | ||
function everySeconds(n, unit, func) { | ||
// Measures start counting at 1, whereas seconds start counting at 0. | ||
@@ -145,29 +221,43 @@ // e.g. "every 4 measures" will generate events at "5, 9, 13" measures. | ||
} | ||
everySecondsRange(n, unit, start, stop, event); | ||
everySecondsRange(n, unit, start, stop, func); | ||
} | ||
function everySecondsRange(n, unit, start, stop, event) { | ||
if (n > 0) { | ||
// Offset by n so that we don't generate an event at the beginning | ||
// of the first period. | ||
var timestamp = start + n; | ||
/** | ||
* @param {number} n | ||
* @param {string} unit - Should be "measures" or "seconds" | ||
* @param {number} start | ||
* @param {number} stop | ||
* @param {function} func - Code to run when event fires | ||
*/ | ||
function everySecondsRange(n, unit, start, stop, func) { | ||
if (n <= 0) { | ||
return; | ||
} | ||
while (timestamp < stop) { | ||
inputEvents.push({ | ||
type: 'cue-' + unit, | ||
event: event, | ||
param: timestamp, | ||
priority: n | ||
}); | ||
timestamp += n; | ||
} | ||
// Offset by n so that we don't generate an event at the beginning | ||
// of the first period. | ||
var timestamp = start + n; | ||
while (timestamp < stop) { | ||
inputEvents.push({ | ||
type: 'cue-' + unit, | ||
func: func, | ||
param: timestamp, | ||
queueType: QueueType.every, | ||
priority: n | ||
}); | ||
timestamp += n; | ||
} | ||
} | ||
function everyVerseChorus(unit, event) { | ||
/** | ||
* @param {string} unit - Should be "verse" or "chorus" | ||
* @param {function} func - Code to run when event fires | ||
*/ | ||
function everyVerseChorus(unit, func) { | ||
inputEvents.push({ | ||
type: 'verseChorus', | ||
event: event, | ||
func: func, | ||
param: unit | ||
}); | ||
} |
@@ -8,2 +8,3 @@ /* eslint-disable no-unused-vars, curly, eqeqeq, babel/semi, semi, no-undef */ | ||
const modifySongData = require('./modifySongData'); | ||
const ResourceLoader = require('./ResourceLoader'); | ||
@@ -26,3 +27,2 @@ function Behavior(func, id, extraArgs) { | ||
const img_base = "https://curriculum.code.org/images/sprites/spritesheet_tp/"; | ||
const SIZE = constants.SIZE; | ||
@@ -43,3 +43,2 @@ const FRAMES = constants.FRAMES; | ||
playSound, | ||
moveNames, | ||
recordReplayLog, | ||
@@ -52,2 +51,5 @@ showMeasureLabel = true, | ||
}, | ||
// For testing: Can provide a custom resource loader class | ||
// to load fixtures and/or isolate us entirely from network activity | ||
resourceLoader = new ResourceLoader(), | ||
}) { | ||
@@ -58,10 +60,4 @@ this.onHandleEvents = onHandleEvents; | ||
this.i18n = i18n; | ||
this.resourceLoader_ = resourceLoader; | ||
this.currentFrameEvents = { | ||
'this.p5_.keyWentDown': {}, | ||
'Dance.fft.isPeak': {}, | ||
'cue-seconds': {}, | ||
'cue-measures': {}, | ||
}; | ||
this.world = { | ||
@@ -107,3 +103,3 @@ height: 400, | ||
this.world.SPRITE_NAMES = constants.SPRITE_NAMES; | ||
this.world.MOVE_NAMES = moveNames || constants.MOVE_NAMES; | ||
this.world.MOVE_NAMES = constants.MOVE_NAMES; | ||
@@ -133,2 +129,3 @@ if (spriteConfig) { | ||
this.p5_ = p5Inst; | ||
this.resourceLoader_.initWithP5(p5Inst); | ||
this.sprites_ = p5Inst.createGroup(); | ||
@@ -143,2 +140,6 @@ p5Inst.preload = () => this.preload(); | ||
teardown() { | ||
this.p5_.remove(); | ||
} | ||
onKeyDown(keyCode) { | ||
@@ -177,2 +178,7 @@ this.p5_._onkeydown({ which: keyCode }); | ||
/** | ||
* @param {Object} timestamps | ||
* @param {number[]} timestamps.measures | ||
* @param {number[]} timestamps.seconds | ||
*/ | ||
addCues(timestamps) { | ||
@@ -193,3 +199,2 @@ // Sort cues | ||
this.p5_.noLoop(); | ||
this.currentFrameEvents.any = false; | ||
@@ -201,31 +206,14 @@ this.world.fg_effect = null; | ||
preload() { | ||
// Load spritesheets compressed to various levels of quality with pngquant | ||
// Pass queryparam ?quality=<quality> to try a particular quality level. | ||
// Only those png assets will be downlaoded. | ||
// Available quality levels: | ||
// 50 - 40% smaller | ||
// 25 - 46% | ||
// 10 - 51% | ||
// 5 - 55% | ||
// 1 - 55% | ||
// 0 - 63% smaller | ||
let qualitySuffix = '-q50'; // Default to q50 for now. Set to '' to go back to full-quality. | ||
const qualitySetting = queryParam('quality'); | ||
if (qualitySetting) { | ||
qualitySuffix = `-q${qualitySetting}`; | ||
document.title = `q${qualitySetting} - ${document.title}`; | ||
} | ||
// Load spritesheet JSON files | ||
this.world.SPRITE_NAMES.forEach(this_sprite => { | ||
ANIMATIONS[this_sprite] = []; | ||
this.world.MOVE_NAMES.forEach(({ name, mirror }, moveIndex) => { | ||
const baseUrl = `${img_base}${this_sprite}_${name}`; | ||
this.p5_.loadJSON(`${baseUrl}.json`, jsonData => { | ||
// Passing true as the 3rd arg to loadSpriteSheet() indicates that we want | ||
// it to load the image as a Image (instead of a p5.Image), which avoids | ||
// a canvas creation. This makes it possible to run on mobile Safari in | ||
// iOS 12 with canvas memory limits. | ||
this.setAnimationSpriteSheet(this_sprite, moveIndex, | ||
this.p5_.loadSpriteSheet(`${baseUrl}${qualitySuffix}.png`, jsonData.frames, true), mirror) | ||
this.resourceLoader_.getAnimationData(animationData => { | ||
this.world.SPRITE_NAMES.forEach(costume => { | ||
const costumeData = animationData[costume.toLowerCase()]; | ||
ANIMATIONS[costume] = []; | ||
this.world.MOVE_NAMES.forEach(({ name: moveName, mirror }, moveIndex) => { | ||
const moveData = costumeData[moveName.toLowerCase()]; | ||
this.setAnimationSpriteSheet( | ||
costume, | ||
moveIndex, | ||
this.resourceLoader_.loadSpriteSheet(moveData.spritesheet, moveData.frames), | ||
mirror | ||
); | ||
}); | ||
@@ -332,3 +320,3 @@ }); | ||
sprite.current_move = 0; | ||
sprite.previous_move = 0; | ||
sprite.previous_move = 0; // I don't think this is used? | ||
@@ -937,10 +925,14 @@ for (var i = 0; i < ANIMATIONS[costume].length; i++) { | ||
/** | ||
* @return {Object} TODO: describe | ||
*/ | ||
updateEvents_() { | ||
const events = this.currentFrameEvents; | ||
const { analysis } = this.songMetadata_ || {}; | ||
events.any = false; | ||
events['this.p5_.keyWentDown'] = {}; | ||
events['Dance.fft.isPeak'] = {}; | ||
events['cue-seconds'] = {}; | ||
events['cue-measures'] = {}; | ||
// Will potentially set the following: | ||
// this.p5_.keyWentDown | ||
// Dance.fft.isPeak | ||
// cue-seconds | ||
// cue-measures | ||
const events = {}; | ||
this.peakThisFrame_ = false; | ||
@@ -950,3 +942,3 @@ | ||
if (this.p5_.keyWentDown(key)) { | ||
events.any = true; | ||
events['this.p5_.keyWentDown'] = events['this.p5_.keyWentDown'] || {} | ||
events['this.p5_.keyWentDown'][key] = true; | ||
@@ -963,3 +955,3 @@ } | ||
if (beats[range]) { | ||
events.any = true; | ||
events['Dance.fft.isPeak'] = events['Dance.fft.isPeak'] || {} | ||
events['Dance.fft.isPeak'][range] = true; | ||
@@ -973,3 +965,3 @@ this.peakThisFrame_ = true; | ||
while (this.world.cues.seconds.length > 0 && this.world.cues.seconds[0] < this.getCurrentTime()) { | ||
events.any = true; | ||
events['cue-seconds'] = events['cue-seconds'] || {} | ||
events['cue-seconds'][this.world.cues.seconds.splice(0, 1)] = true; | ||
@@ -979,5 +971,7 @@ } | ||
while (this.world.cues.measures.length > 0 && this.world.cues.measures[0] < this.getCurrentMeasure()) { | ||
events.any = true; | ||
events['cue-measures'] = events['cue-measures'] || {}; | ||
events['cue-measures'][this.world.cues.measures.splice(0, 1)] = true; | ||
} | ||
return events; | ||
} | ||
@@ -1014,3 +1008,3 @@ | ||
draw() { | ||
this.updateEvents_(); | ||
const events = this.updateEvents_(); | ||
this.sampleFrameRate_(); | ||
@@ -1067,4 +1061,4 @@ | ||
if (this.currentFrameEvents.any && this.onHandleEvents) { | ||
this.onHandleEvents(this.currentFrameEvents); | ||
if (Object.keys(events).length && this.onHandleEvents) { | ||
this.onHandleEvents(events); | ||
} | ||
@@ -1071,0 +1065,0 @@ } |
const DanceParty = require('../../src/p5.dance'); | ||
const UnitTestResourceLoader = require('./UnitTestResourceLoader'); | ||
@@ -7,9 +8,9 @@ module.exports = { | ||
new DanceParty({ | ||
moveNames: [], | ||
playSound: (url, callback) => callback(), | ||
onInit: nativeAPI => resolve(nativeAPI), | ||
resourceLoader: new UnitTestResourceLoader(), | ||
...props | ||
}); | ||
}); | ||
} | ||
}, | ||
}; |
const {createDanceAPI} = require('./createDanceAPI'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const interpreted = fs.readFileSync(path.join(__dirname, '..', '..', 'src', 'p5.dance.interpreted.js'), 'utf8'); | ||
const ResourceLoader = require('../../src/ResourceLoader'); | ||
const interpreted = require('raw-loader!../../src/p5.dance.interpreted.js'); | ||
const injectInterpreted = require('./injectInterpreted'); | ||
@@ -11,5 +9,7 @@ | ||
createDanceAPI({ | ||
resourceLoader: new ResourceLoader('/base/assets/sprite_sheets/'), | ||
onPuzzleComplete: (result, message) => { | ||
onPuzzleComplete(result, message); | ||
nativeAPI.reset(); | ||
nativeAPI.teardown(); | ||
}, | ||
@@ -28,16 +28,2 @@ onInit: api => { | ||
// Mock 4 cat and moose animation poses. | ||
const moveCount = 10; | ||
for (let i = 0; i < moveCount; i++) { | ||
api.setAnimationSpriteSheet("CAT", i, {}, () => {}); | ||
api.setAnimationSpriteSheet("MOOSE", i, {}, () => {}); | ||
api.setAnimationSpriteSheet("ROBOT", i, {}, () => {}); | ||
api.world.MOVE_NAMES.push({ | ||
name: `move${i}` | ||
}); | ||
} | ||
api.world.fullLengthMoveCount = moveCount; | ||
api.world.restMoveCount = 1; | ||
api.addCues(getCueList()); | ||
@@ -44,0 +30,0 @@ api.onHandleEvents = currentFrameEvents => runUserEvents(currentFrameEvents); |
const test = require('tape'); | ||
const helpers = require('../helpers/createDanceAPI'); | ||
test('getCues sorts measures and seconds cues', async t => { | ||
test('addCues sorts measures and seconds cues', async t => { | ||
const nativeAPI = await helpers.createDanceAPI(); | ||
@@ -35,2 +35,1 @@ nativeAPI.play({ | ||
}); | ||
const test = require('tape'); | ||
const helpers = require('../helpers/createDanceAPI'); | ||
test('setBackground changes the bgEffect to color_cycle effect', async t => { | ||
test('setBackground clears the bgEffect and sets background_color', async t => { | ||
const nativeAPI = await helpers.createDanceAPI(); | ||
nativeAPI.setBackgroundEffect('diamonds'); | ||
// Initial Values | ||
t.equal(nativeAPI.world.bg_effect, 'diamonds'); | ||
nativeAPI.setBackground('purple'); | ||
t.equal(nativeAPI.world.background_color, 'purple'); | ||
t.equal(nativeAPI.world.bg_effect, null); | ||
t.end(); | ||
nativeAPI.reset(); | ||
}); | ||
test('setBackgroundEffect changes the bgEffect to color_cycle effect', async t => { | ||
const nativeAPI = await helpers.createDanceAPI(); | ||
// Initial Values | ||
t.equal(nativeAPI.world.bg_effect, null); | ||
nativeAPI.setBackgroundEffect('color_cycle'); | ||
@@ -11,0 +27,0 @@ |
const test = require('tape'); | ||
const constants = require('../../src/constants'); | ||
const helpers = require('../helpers/createDanceAPI'); | ||
const UnitTestResourceLoader = require('../helpers/UnitTestResourceLoader'); | ||
@@ -180,3 +182,6 @@ test('Sprite dance decrements and loops for prev dance', async t => { | ||
const subTest = async ({ moveCount = 3, testCode }) => { | ||
const nativeAPI = await helpers.createDanceAPI(); | ||
// These tests set up their own moves, assuming no initial moves | ||
const nativeAPI = await helpers.createDanceAPI({ | ||
spriteConfig: world => world.MOVE_NAMES = [] | ||
}); | ||
nativeAPI.play({ | ||
@@ -256,22 +261,7 @@ bpm: 120, | ||
test('Sprite move sorting works reliably', async t => { | ||
const P5 = require('../../src/loadP5'); | ||
P5.prototype.loadJSON = function (_url, callback) { | ||
setTimeout(() => { | ||
this._preloadCount--; | ||
this._runIfPreloadsAreDone(); | ||
callback('{"frames":{}}'); | ||
}, 0); | ||
}; | ||
P5.prototype.loadImageElement = function (_url, callback) { | ||
setTimeout(() => { | ||
this._preloadCount--; | ||
this._runIfPreloadsAreDone(); | ||
callback(new Image()); | ||
}, 0); | ||
}; | ||
const subTest = async ({ moveNames, testCode }) => { | ||
const nativeAPI = await helpers.createDanceAPI({ moveNames, spriteConfig: world => { world.SPRITE_NAMES = ['foo']; } }); | ||
const nativeAPI = await helpers.createDanceAPI({ | ||
spriteConfig: world => { world.MOVE_NAMES = moveNames; }, | ||
resourceLoader: new UnitTestResourceLoader(constants.SPRITE_NAMES, moveNames), | ||
}); | ||
@@ -278,0 +268,0 @@ nativeAPI.p5_.noLoop(); |
@@ -18,4 +18,4 @@ const test = require('tape'); | ||
nativeAPI.updateEvents_(); | ||
t.deepEqual(nativeAPI.currentFrameEvents['this.p5_.keyWentDown'], { | ||
const events = nativeAPI.updateEvents_(); | ||
t.deepEqual(events['this.p5_.keyWentDown'], { | ||
left: true, | ||
@@ -22,0 +22,0 @@ space: true, |
module.exports = { | ||
devtool: 'eval-cheap-module-source-map', | ||
entry: { | ||
@@ -3,0 +4,0 @@ main: './src/index.js', |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
21292203
96
1
1
4
25
107809