Comparing version 0.2.0 to 0.3.0
382
index.js
"use strict"; | ||
//TODO: | ||
//- scan blocks for declaration statements before executing incl. handle | ||
// undefined + maybe es5 reference errors in strict mode | ||
//- SwitchStatement | ||
//- LabeledStatement -> including use in break/continue | ||
@@ -36,19 +33,21 @@ //-> TESTS | ||
function Environment(scopesOrGlobalObj) { | ||
if (!Array.isArray(scopesOrGlobalObj)) { | ||
scopesOrGlobalObj = [scopesOrGlobalObj]; | ||
function Environment(globalObjects) { | ||
if (!Array.isArray(globalObjects)) { | ||
globalObjects = [globalObjects]; | ||
} | ||
var parent; | ||
scopesOrGlobalObj.forEach(function (vars) { | ||
parent = createScope(vars, parent); | ||
globalObjects.forEach(function (vars) { | ||
parent = createVarStore(parent, vars); | ||
}); | ||
// the topmost scope is our current scope | ||
this._curScope = parent; | ||
this._globalObj = scopesOrGlobalObj[0]; | ||
// the topmost store is our current store | ||
this._curVarStore = parent; | ||
this._curDeclarations = []; | ||
this._globalObj = globalObjects[0]; | ||
this._curThis = this._globalObj; | ||
this._boundGen = this.gen.bind(this); | ||
this._boundGen = this._gen.bind(this); | ||
} | ||
function createScope(vars, parent) { | ||
function createVarStore(parent, vars) { | ||
vars = vars || {}; | ||
return { | ||
@@ -61,36 +60,44 @@ parent: parent, | ||
Environment.prototype.gen = function (node) { | ||
var resp = this._gen(node); | ||
addDeclarationsToStore(this._curDeclarations, this._curVarStore); | ||
this._curDeclarations = []; | ||
return resp; | ||
}; | ||
Environment.prototype._gen = function (node) { | ||
return ({ | ||
BinaryExpression: this.genBinExpr, | ||
LogicalExpression: this.genBinExpr, | ||
UnaryExpression: this.genUnaryExpr, | ||
UpdateExpression: this.genUpdExpr, | ||
ObjectExpression: this.genObjExpr, | ||
ArrayExpression: this.genArrExpr, | ||
CallExpression: this.genCallExpr, | ||
NewExpression: this.genNewExpr, | ||
MemberExpression: this.genMemExpr, | ||
ThisExpression: this.genThisExpr, | ||
SequenceExpression: this.genSeqExpr, | ||
Literal: this.genLit, | ||
Identifier: this.genIdent, | ||
AssignmentExpression: this.genAssignExpr, | ||
FunctionDeclaration: this.genFuncDecl, | ||
VariableDeclaration: this.genVarDecl, | ||
BlockStatement: this.genProgram, | ||
Program: this.genProgram, | ||
ExpressionStatement: this.genExprStmt, | ||
EmptyStatement: this.genEmptyStmt, | ||
ReturnStatement: this.genRetStmt, | ||
FunctionExpression: this.genFuncExpr, | ||
IfStatement: this.genIfStmt, | ||
ConditionalExpression: this.genIfStmt, | ||
ForStatement: this.genLoopStmt, | ||
WhileStatement: this.genLoopStmt, | ||
DoWhileStatement: this.genDoWhileStmt, | ||
ForInStatement: this.genForInStmt, | ||
WithStatement: this.genWithStmt, | ||
ThrowStatement: this.genThrowStmt, | ||
TryStatement: this.genTryStmt, | ||
ContinueStatement: this.genContStmt, | ||
BreakStatement: this.genBreakStmt, | ||
BinaryExpression: this._genBinExpr, | ||
LogicalExpression: this._genBinExpr, | ||
UnaryExpression: this._genUnaryExpr, | ||
UpdateExpression: this._genUpdExpr, | ||
ObjectExpression: this._genObjExpr, | ||
ArrayExpression: this._genArrExpr, | ||
CallExpression: this._genCallExpr, | ||
NewExpression: this._genNewExpr, | ||
MemberExpression: this._genMemExpr, | ||
ThisExpression: this._genThisExpr, | ||
SequenceExpression: this._genSeqExpr, | ||
Literal: this._genLit, | ||
Identifier: this._genIdent, | ||
AssignmentExpression: this._genAssignExpr, | ||
FunctionDeclaration: this._genFuncDecl, | ||
VariableDeclaration: this._genVarDecl, | ||
BlockStatement: this._genProgram, | ||
Program: this._genProgram, | ||
ExpressionStatement: this._genExprStmt, | ||
EmptyStatement: this._genEmptyStmt, | ||
ReturnStatement: this._genRetStmt, | ||
FunctionExpression: this._genFuncExpr, | ||
IfStatement: this._genIfStmt, | ||
ConditionalExpression: this._genIfStmt, | ||
ForStatement: this._genLoopStmt, | ||
WhileStatement: this._genLoopStmt, | ||
DoWhileStatement: this._genDoWhileStmt, | ||
ForInStatement: this._genForInStmt, | ||
WithStatement: this._genWithStmt, | ||
ThrowStatement: this._genThrowStmt, | ||
TryStatement: this._genTryStmt, | ||
ContinueStatement: this._genContStmt, | ||
BreakStatement: this._genBreakStmt, | ||
SwitchStatement: this._genSwitchStmt, | ||
}[node.type] || function () { | ||
@@ -102,3 +109,3 @@ console.warn("Not implemented yet: " + node.type); | ||
Environment.prototype.genBinExpr = function (node) { | ||
Environment.prototype._genBinExpr = function (node) { | ||
var cmp = { | ||
@@ -131,4 +138,4 @@ '==': function (a, b) {return a == b; }, | ||
var left = this.gen(node.left); | ||
var right = this.gen(node.right); | ||
var left = this._gen(node.left); | ||
var right = this._gen(node.right); | ||
return function () { | ||
@@ -139,3 +146,3 @@ return cmp(left(), right()); | ||
Environment.prototype.genUnaryExpr = function (node) { | ||
Environment.prototype._genUnaryExpr = function (node) { | ||
var op = { | ||
@@ -151,3 +158,3 @@ '-': function (a) {return -a; }, | ||
}[node.operator]; | ||
var argument = this.gen(node.argument); | ||
var argument = this._gen(node.argument); | ||
@@ -159,3 +166,3 @@ return function () { | ||
Environment.prototype.genObjExpr = function (node) { | ||
Environment.prototype._genObjExpr = function (node) { | ||
//TODO property.kind: don't assume init when it can also be set/get | ||
@@ -170,3 +177,3 @@ var self = this; | ||
key: key, | ||
getVal: self.gen(property.value) | ||
getVal: self._gen(property.value) | ||
}); | ||
@@ -184,3 +191,3 @@ }); | ||
Environment.prototype.genArrExpr = function (node) { | ||
Environment.prototype._genArrExpr = function (node) { | ||
var items = node.elements.map(this._boundGen); | ||
@@ -197,3 +204,3 @@ return function () { | ||
} else { | ||
key = this.gen(node)(); | ||
key = this._gen(node)(); | ||
} | ||
@@ -203,3 +210,3 @@ return function () {return key; }; | ||
Environment.prototype.genCallExpr = function (node) { | ||
Environment.prototype._genCallExpr = function (node) { | ||
var self = this; | ||
@@ -216,5 +223,5 @@ | ||
} else { | ||
callee = self.gen(node.callee); | ||
callee = self._gen(node.callee); | ||
} | ||
var args = node.arguments.map(self.gen.bind(self)); | ||
var args = node.arguments.map(self._gen.bind(self)); | ||
return function () { | ||
@@ -225,4 +232,4 @@ return callee().apply(self._globalObj, args.map(execute)); | ||
Environment.prototype.genNewExpr = function (node) { | ||
var callee = this.gen(node.callee); | ||
Environment.prototype._genNewExpr = function (node) { | ||
var callee = this._gen(node.callee); | ||
var args = node.arguments.map(this._boundGen); | ||
@@ -239,4 +246,4 @@ return function () { | ||
Environment.prototype.genMemExpr = function (node) { | ||
var obj = this.gen(node.object); | ||
Environment.prototype._genMemExpr = function (node) { | ||
var obj = this._gen(node.object); | ||
var property = this._memExprProperty(node); | ||
@@ -249,6 +256,6 @@ return function () { | ||
Environment.prototype._memExprProperty = function (node) { | ||
return node.computed ? this.gen(node.property) : this._objKey(node.property); | ||
return node.computed ? this._gen(node.property) : this._objKey(node.property); | ||
}; | ||
Environment.prototype.genThisExpr = function () { | ||
Environment.prototype._genThisExpr = function () { | ||
var self = this; | ||
@@ -258,3 +265,3 @@ return function () {return self._curThis; }; | ||
Environment.prototype.genSeqExpr = function (node) { | ||
Environment.prototype._genSeqExpr = function (node) { | ||
var exprs = node.expressions.map(this._boundGen); | ||
@@ -270,3 +277,3 @@ return function () { | ||
Environment.prototype.genUpdExpr = function (node) { | ||
Environment.prototype._genUpdExpr = function (node) { | ||
var update = { | ||
@@ -287,5 +294,5 @@ '--true': function (obj, name) {return --obj[name]; }, | ||
if (node.type === 'Identifier') { | ||
return this._getScopeVars.bind(this, node.name); | ||
return this._getVarStore.bind(this, node.name); | ||
} else if (node.type === 'MemberExpression') { | ||
return this.gen(node.object); | ||
return this._gen(node.object); | ||
} else { | ||
@@ -308,3 +315,3 @@ console.warn("Unknown _genObj() type: " + node.type); | ||
Environment.prototype.genLit = function (node) { | ||
Environment.prototype._genLit = function (node) { | ||
return function () { | ||
@@ -315,22 +322,22 @@ return node.value; | ||
Environment.prototype.genIdent = function (node) { | ||
Environment.prototype._genIdent = function (node) { | ||
var self = this; | ||
return function () { | ||
return self._getScopeVars(node.name)[node.name]; | ||
return self._getVarStore(node.name)[node.name]; | ||
}; | ||
}; | ||
Environment.prototype._getScopeVars = function (name) { | ||
var scope = this._curScope; | ||
Environment.prototype._getVarStore = function (name) { | ||
var store = this._curVarStore; | ||
do { | ||
if (scope.vars.hasOwnProperty(name)) { | ||
return scope.vars; | ||
if (store.vars.hasOwnProperty(name)) { | ||
return store.vars; | ||
} | ||
} while ((scope = scope.parent)); | ||
} while ((store = store.parent)); | ||
// global scope if no other scope has been found | ||
return this._globalObject; | ||
// global object as fallback | ||
return this._globalObj; | ||
}; | ||
Environment.prototype.genAssignExpr = function (node) { | ||
Environment.prototype._genAssignExpr = function (node) { | ||
var setter = { | ||
@@ -352,3 +359,3 @@ '=': function (obj, name, val) {return (obj[name] = val); }, | ||
var name = this._genName(node.left); | ||
var val = this.gen(node.right); | ||
var val = this._gen(node.right); | ||
return function () { | ||
@@ -359,34 +366,46 @@ return setter(obj(), name(), val()); | ||
Environment.prototype.genFuncDecl = function (node) { | ||
var self = this; | ||
var func = self.genFuncExpr(node); | ||
return function () { | ||
self._curScope.vars[node.id.name] = func(); | ||
}; | ||
Environment.prototype._genFuncDecl = function (node) { | ||
this._curDeclarations.push(node.id.name); | ||
node.type = 'FunctionExpression'; | ||
return this._gen({ | ||
type: 'AssignmentExpression', | ||
operator: '=', | ||
left: node.id, | ||
right: node | ||
}); | ||
}; | ||
Environment.prototype.genVarDecl = function (node) { | ||
var self = this; | ||
var decls = node.declarations.map(function (decl) { | ||
return { | ||
name: decl.id.name, | ||
getVal: decl.init ? self.gen(decl.init) : noop, | ||
}; | ||
Environment.prototype._genVarDecl = function (node) { | ||
var assignments = []; | ||
for (var i = 0; i < node.declarations.length; i++) { | ||
var decl = node.declarations[i]; | ||
this._curDeclarations.push(decl.id.name); | ||
if (decl.init) { | ||
assignments.push({ | ||
type: 'AssignmentExpression', | ||
operator: '=', | ||
left: decl.id, | ||
right: decl.init | ||
}); | ||
} | ||
} | ||
return this._gen({ | ||
type: 'BlockStatement', | ||
body: assignments | ||
}); | ||
return function () { | ||
decls.forEach(function (decl) { | ||
self._curScope.vars[decl.name] = decl.getVal(); | ||
}); | ||
}; | ||
}; | ||
Environment.prototype.genFuncExpr = function (node) { | ||
Environment.prototype._genFuncExpr = function (node) { | ||
var self = this; | ||
self._curScope = createScope({}, self._curScope); | ||
var body = self.gen(node.body); | ||
// reset scope | ||
var scope = self._curScope; | ||
self._curScope = scope.parent; | ||
var oldDeclarations = self._curDeclarations; | ||
self._curDeclarations = []; | ||
var body = self._gen(node.body); | ||
var declarations = self._curDeclarations; | ||
self._curDeclarations = oldDeclarations; | ||
// reset var store | ||
return function () { | ||
var parent = self._curVarStore; | ||
return function () { | ||
@@ -399,12 +418,15 @@ // build arguments object | ||
} | ||
scope.vars.arguments = args; | ||
// add function args to scope | ||
var varStore = createVarStore(parent); | ||
addDeclarationsToStore(declarations, varStore); | ||
varStore.vars.arguments = args; | ||
// add function args to var store | ||
node.params.forEach(function (param, i) { | ||
scope.vars[param.name] = args[i]; | ||
varStore.vars[param.name] = args[i]; | ||
}); | ||
// switch interpreter 'stack' | ||
var oldScope = self._curScope; | ||
var oldStore = self._curVarStore; | ||
var oldThis = self._curThis; | ||
self._curScope = scope; | ||
self._curVarStore = varStore; | ||
self._curThis = this; | ||
@@ -417,3 +439,3 @@ | ||
self._curThis = oldThis; | ||
self._curScope = oldScope; | ||
self._curVarStore = oldStore; | ||
@@ -427,6 +449,14 @@ if (result instanceof Return) { | ||
Environment.prototype.genProgram = function (node) { | ||
function addDeclarationsToStore(declarations, varStore) { | ||
for (var i = 0; i < declarations.length; i++) { | ||
if (!varStore.vars.hasOwnProperty(declarations[i])) { | ||
varStore.vars[declarations[i]] = undefined; | ||
} | ||
} | ||
} | ||
Environment.prototype._genProgram = function (node) { | ||
var self = this; | ||
var stmtClosures = node.body.map(function (stmt) { | ||
return self.gen(stmt); | ||
return self._gen(stmt); | ||
}); | ||
@@ -446,12 +476,12 @@ return function () { | ||
Environment.prototype.genExprStmt = function (node) { | ||
return this.gen(node.expression); | ||
Environment.prototype._genExprStmt = function (node) { | ||
return this._gen(node.expression); | ||
}; | ||
Environment.prototype.genEmptyStmt = function () { | ||
Environment.prototype._genEmptyStmt = function () { | ||
return noop; | ||
}; | ||
Environment.prototype.genRetStmt = function (node) { | ||
var arg = this.gen(node.argument); | ||
Environment.prototype._genRetStmt = function (node) { | ||
var arg = this._gen(node.argument); | ||
return function () { | ||
@@ -462,6 +492,6 @@ return new Return(arg()); | ||
Environment.prototype.genIfStmt = function (node) { | ||
var test = this.gen(node.test); | ||
var consequent = this.gen(node.consequent); | ||
var alternate = node.alternate ? this.gen(node.alternate) : noop; | ||
Environment.prototype._genIfStmt = function (node) { | ||
var test = this._gen(node.test); | ||
var consequent = this._gen(node.consequent); | ||
var alternate = node.alternate ? this._gen(node.alternate) : noop; | ||
@@ -473,9 +503,9 @@ return function () { | ||
Environment.prototype.genLoopStmt = function (node, body) { | ||
var init = node.init ? this.gen(node.init) : noop; | ||
var test = node.test ? this.gen(node.test) : function () { | ||
Environment.prototype._genLoopStmt = function (node, body) { | ||
var init = node.init ? this._gen(node.init) : noop; | ||
var test = node.test ? this._gen(node.test) : function () { | ||
return true; | ||
}; | ||
var update = node.update ? this.gen(node.update) : noop; | ||
body = body || this.gen(node.body); | ||
var update = node.update ? this._gen(node.update) : noop; | ||
body = body || this._gen(node.body); | ||
@@ -501,5 +531,5 @@ return function () { | ||
Environment.prototype.genDoWhileStmt = function (node) { | ||
var body = this.gen(node.body); | ||
var loop = this.genLoopStmt(node, body); | ||
Environment.prototype._genDoWhileStmt = function (node) { | ||
var body = this._gen(node.body); | ||
var loop = this._genLoopStmt(node, body); | ||
@@ -512,7 +542,7 @@ return function () { | ||
Environment.prototype.genForInStmt = function (node) { | ||
Environment.prototype._genForInStmt = function (node) { | ||
/* var self = this; | ||
var left = self.gen(node.left); | ||
var right = self.gen(node.right); | ||
var body = self.gen(node.body); | ||
var left = self._gen(node.left); | ||
var right = self._gen(node.right); | ||
var body = self._gen(node.body); | ||
@@ -526,3 +556,3 @@ var left = node.left; | ||
for (x in right()) { | ||
self.genAssignExpr({ | ||
self._genAssignExpr({ | ||
left: left, | ||
@@ -541,11 +571,10 @@ right: { | ||
Environment.prototype.genWithStmt = function (node) { | ||
Environment.prototype._genWithStmt = function (node) { | ||
var self = this; | ||
var obj = self.gen(node.object); | ||
var body = self.gen(node.body); | ||
var obj = self._gen(node.object); | ||
var body = self._gen(node.body); | ||
return function () { | ||
var prevScope = self._curScope; | ||
self._curScope = createScope(obj(), prevScope); | ||
self._curVarStore = createVarStore(self._curVarStore, obj()); | ||
var result = body(); | ||
self._curScope = prevScope; | ||
self._curVarStore = self._curVarStore.parent; | ||
return result; | ||
@@ -555,4 +584,4 @@ }; | ||
Environment.prototype.genThrowStmt = function (node) { | ||
var arg = this.gen(node.argument); | ||
Environment.prototype._genThrowStmt = function (node) { | ||
var arg = this._gen(node.argument); | ||
return function () { | ||
@@ -563,6 +592,6 @@ throw arg(); | ||
Environment.prototype.genTryStmt = function (node) { | ||
var block = this.gen(node.block); | ||
Environment.prototype._genTryStmt = function (node) { | ||
var block = this._gen(node.block); | ||
var handler = this._genCatchHandler(node.handler); | ||
var finalizer = node.finalizer ? this.gen(node.finalizer) : null; | ||
var finalizer = node.finalizer ? this._gen(node.finalizer) : null; | ||
@@ -588,8 +617,8 @@ return function () { | ||
var self = this; | ||
var body = self.gen(node.body); | ||
var body = self._gen(node.body); | ||
return function (err) { | ||
var old = self._curScope[node.param.name]; | ||
self._curScope[node.param.name] = err; | ||
var old = self._curVarStore.vars[node.param.name]; | ||
self._curVarStore.vars[node.param.name] = err; | ||
var resp = body(); | ||
self._curScope[node.param.name] = old; | ||
self._curVarStore.vars[node.param.name] = old; | ||
@@ -600,21 +629,62 @@ return resp; | ||
Environment.prototype.genContStmt = function () { | ||
Environment.prototype._genContStmt = function () { | ||
return function () {return Continue; }; | ||
}; | ||
Environment.prototype.genBreakStmt = function () { | ||
Environment.prototype._genBreakStmt = function () { | ||
return function () {return Break; }; | ||
}; | ||
Environment.prototype._genSwitchStmt = function (node) { | ||
var self = this; | ||
var discriminant = self._gen(node.discriminant); | ||
var cases = node.cases.map(function (curCase) { | ||
return { | ||
test: curCase.test ? self._gen(curCase.test) : null, | ||
code: self._genProgram({body: curCase.consequent}) | ||
}; | ||
}); | ||
return function () { | ||
var foundMatch = false; | ||
var discriminantVal = discriminant(); | ||
var resp, defaultCase; | ||
for (var i = 0; i < cases.length; i++) { | ||
var curCase = cases[i]; | ||
if (!foundMatch) { | ||
if (!curCase.test) { | ||
defaultCase = curCase; | ||
continue; | ||
} | ||
if (discriminantVal !== curCase.test()) { | ||
continue; | ||
} | ||
foundMatch = true; | ||
} | ||
// foundMatch is guaranteed to be true here | ||
var newResp = curCase.code(); | ||
if (newResp === Break) { | ||
return resp; | ||
} | ||
resp = newResp; | ||
if (resp === Continue || resp instanceof Return) { | ||
return resp; | ||
} | ||
} | ||
if (!foundMatch && defaultCase) { | ||
return defaultCase.code(); | ||
} | ||
}; | ||
}; | ||
exports.Environment = Environment; | ||
var evaling = false; | ||
exports.evaluate = function (code) { | ||
var ast = parse(code); | ||
evaling = true; | ||
var env = new Environment(global); | ||
var resp = env.gen(ast)(); | ||
evaling = false; | ||
return resp; | ||
}; | ||
console.log(exports.evaluate("2 + 1")); | ||
//console.log(exports.evaluate("1 + 1")); |
{ | ||
"name": "evaljs", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "A JavaScript interpreter written in JavaScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -10,4 +10,2 @@ eval.js | ||
ATTENTION: THIS IS A WORK-IN-PROGRESS | ||
Why? | ||
@@ -60,2 +58,9 @@ ---- | ||
Is it complete? | ||
--------------- | ||
No labeled statements; no nice error handling; there are probably bugs. | ||
That said, it can run itself so it's supported subset of JS is usable. | ||
PRs welcome! | ||
How slow is it? | ||
@@ -62,0 +67,0 @@ --------------- |
@@ -9,2 +9,8 @@ "use strict"; | ||
var env = new evaljs.Environment([{console: console}]); | ||
env.gen(parse(code))(); | ||
//index.js | ||
var code = fs.readFileSync('index.js', {encoding: 'UTF-8'}); | ||
var envGlobal = {console: console, Array: Array, Error: Error, Object: Object}; | ||
@@ -11,0 +17,0 @@ envGlobal.global = global; |
@@ -6,3 +6,6 @@ // not strict, 'cause we need to parse the with statement | ||
/* jshint -W027 */ | ||
// missing break statements in switch statements are ok | ||
/* jshint -W086 */ | ||
/* | ||
var op = { | ||
@@ -93,3 +96,17 @@ '+': function (a, b) {return a + b; } | ||
/* | ||
console.log(function () { | ||
var x = 4; | ||
console.log(1); | ||
if (x) { | ||
console.log(2); | ||
for (var i = 0; i < 3; i++) { | ||
console.log(3); | ||
return x; | ||
console.log(5); | ||
} | ||
console.log(6); | ||
} | ||
console.log(7); | ||
}()); | ||
*/ | ||
var x = 2; | ||
@@ -99,2 +116,3 @@ switch (x) { | ||
console.log(1); | ||
//falls through | ||
case 2: | ||
@@ -104,8 +122,46 @@ console.log(2); | ||
console.log(3); | ||
break | ||
break; | ||
case 4: | ||
console.log(4); | ||
default: | ||
console.log(5); | ||
} | ||
*/ | ||
switch (x) { | ||
case 1: | ||
console.log(1); | ||
default: | ||
console.log(2); | ||
} | ||
switch (x) { | ||
case 2: | ||
console.log(3); | ||
break; | ||
default: | ||
console.log(4); | ||
} | ||
switch (x) { | ||
case 2: | ||
console.log(5); | ||
default: | ||
console.log(6); | ||
} | ||
switch (x) { | ||
default: | ||
console.log(7); | ||
case 2: | ||
console.log(8); | ||
} | ||
switch (x) { | ||
default: | ||
console.log(9); | ||
break; | ||
case 2: | ||
console.log(10); | ||
} | ||
/* | ||
@@ -122,16 +178,1 @@ for (var key in {a: 1, b: 2}) { | ||
/*jshint ignore:end*/ | ||
console.log(function () { | ||
var x = 4; | ||
console.log(1); | ||
if (x) { | ||
console.log(2); | ||
for (var i = 0; i < 3; i++) { | ||
console.log(3); | ||
return x; | ||
console.log(5); | ||
} | ||
console.log(6); | ||
} | ||
console.log(7); | ||
}()); |
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
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
181415
3702
77