Socket
Socket
Sign inDemoInstall

context-parser-handlebars

Package Overview
Dependencies
Maintainers
4
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

context-parser-handlebars - npm Package Compare versions

Comparing version 1.0.5 to 1.0.6

tests/samples/bugs/006.state.attribute-name.hb

2

package.json
{
"name": "context-parser-handlebars",
"version": "1.0.5",
"version": "1.0.6",
"licenses": [

@@ -5,0 +5,0 @@ {

@@ -37,2 +37,15 @@ /*

// extracted from xss-filters
/*
['^(?:',
[
'[\\u0000-\\u0020]',
'&#[xX]0*(?:1?[1-9a-fA-F]|10|20);?', // &#x1-20 in hex
'&#0*(?:[1-9]|[1-2][0-9]|30|31|32);?', // &#1-32 in dec
'	', '
' // space, newline in char entities
].join('|'),
')*'].join('');
*/
var reURIContextStartWhitespaces = /^(?:[\u0000-\u0020]|&#[xX]0*(?:1?[1-9a-fA-F]|10|20);?|&#0*(?:[1-9]|[1-2][0-9]|30|31|32);?|	|
)*/;
/**

@@ -70,3 +83,54 @@ * @module ContextParserHandlebars

// TODO: use util
// @function ContextParser.getInternalState
contextParser.Parser.prototype.getInternalState = function() {
var stateObj = {};
stateObj.state = this.state;
stateObj.tagNames = this.tagNames;
stateObj.tagNameIdx = this.tagNameIdx;
stateObj.attributeName = this.attributeName;
stateObj.attributeValue = this.attributeValue;
return stateObj;
};
// @function ContextParser.setInternalState
contextParser.Parser.prototype.setInternalState = function(stateObj) {
// TODO: these 2 apis need to combine.
this.setInitState(stateObj.state);
this.setCurrentState(stateObj.state);
this.tagNames = stateObj.tagNames.slice(0); // need deep copy
this.tagNameIdx = stateObj.tagNameIdx;
this.attributeName = stateObj.attributeName;
this.attributeValue = stateObj.attributeValue;
};
// @function ContextParser._deepCompareState
contextParser.Parser.prototype._deepCompareState = function(stateObj1, stateObj2) {
var r = true;
[ 'state', // test for the HTML5 state.
// 'tagNameIdx', // test for the close tag in the branching logic, but it is not balanced.
// 'attributeName', 'attributeValue' // not necessary the same in branching logic.
].some(function(key) {
if (stateObj1[key] !== '' && stateObj2[key] !== '' && stateObj1[key] !== stateObj2[key]) {
r = false;
}
});
/*
[
// 'tagNames' // not necessary the same in branching logic.
].forEach(function(key) {
if (!(stateObj1[key] instanceof Array) || !(stateObj2[key] instanceof Array)) {
r = false;
return;
}
for(var i=0;i<stateObj1[key].length;++i) {
if (stateObj1[key][i] !== stateObj2[key][i]) {
r = false;
}
}
});
*/
return r;
};
/* inherit the prototype of contextParser.Parser */

@@ -145,3 +209,3 @@ ContextParserHandlebars.prototype = Object.create(contextParser.Parser.prototype);

/* transitent var */
var e, f, msg, exceptionObj;
var isFullUri, f, msg, exceptionObj;

@@ -156,186 +220,167 @@ /* return filters */

// 1
if (state === stateMachine.State.STATE_DATA) {
filters.push(filter.FILTER_DATA);
return filters;
// 3
} else if (state === stateMachine.State.STATE_RCDATA) {
filters.push(filter.FILTER_DATA);
return filters;
// 5
} else if (state === stateMachine.State.STATE_RAWTEXT) {
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_RAWTEXT state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
// 6
} else if (state === stateMachine.State.STATE_SCRIPT_DATA) {
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_SCRIPT_DATA state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
// 34
} else if (state === stateMachine.State.STATE_BEFORE_ATTRIBUTE_NAME) {
/* never fall into this state */
// 35
} else if (state === stateMachine.State.STATE_ATTRIBUTE_NAME) {
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_ATTRIBUTE_NAME state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
// 36
} else if (state === stateMachine.State.STATE_AFTER_ATTRIBUTE_NAME) {
/* never fall into this state, please refer to tests/unit/run-states-spec.js */
// 37
} else if (state === stateMachine.State.STATE_BEFORE_ATTRIBUTE_VALUE) {
/* never fall into this state, please refer to tests/unit/run-states-spec.js */
// 38, 39, 40 + URI scheme
} else if ((state === stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED) &&
(attributeName === "href" || attributeName === "src" || attributeName === "action" || attributeName === "formaction" || attributeName === "background" || attributeName === "cite" || attributeName === "longdesc" || attributeName === "usemap" || attributeName === "xlink:href")
) {
/* we don't support javascript parsing yet */
// TODO: this filtering rule cannot cover all cases.
if (handlebarsUtils.blacklistProtocol(attributeValue)) {
switch(state) {
case stateMachine.State.STATE_DATA: // 1
filters.push(filter.FILTER_DATA);
return filters;
case stateMachine.State.STATE_RCDATA: // 3
filters.push(filter.FILTER_DATA);
return filters;
case stateMachine.State.STATE_RAWTEXT: // 5
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ attribute URI Javascript context.";
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_RAWTEXT state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
/* this one is safe to return */
return filters;
}
case stateMachine.State.STATE_SCRIPT_DATA: // 6
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_SCRIPT_DATA state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
case stateMachine.State.STATE_BEFORE_ATTRIBUTE_NAME: // 34
/* never fall into state 34 */
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unexpected output expression @ STATE_BEFORE_ATTRIBUTE_NAME state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
case stateMachine.State.STATE_ATTRIBUTE_NAME: // 35
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_ATTRIBUTE_NAME state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
case stateMachine.State.STATE_AFTER_ATTRIBUTE_NAME: // 36
/* never fall into state 36 */
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unexpected output expression @ STATE_AFTER_ATTRIBUTE_NAME state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
case stateMachine.State.STATE_BEFORE_ATTRIBUTE_VALUE: // 37
/* never fall into state 37 */
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unexpected output expression @ STATE_BEFORE_ATTRIBUTE_VALUE state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED: // 38
case stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED: // 39
case stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED: // 40
/* add the correct uri filter */
var isFullUri = true;
if (attributeValue.trim() === "") {
f = filter.FILTER_FULL_URI;
} else {
isFullUri = false;
f = filter.FILTER_ENCODE_URI;
e = attributeValue.length;
for(var i=0;i<e;++i) {
if (attributeValue[i] === '=') {
f = filter.FILTER_ENCODE_URI_COMPONENT;
// URI scheme
if (attributeName === "href" || attributeName === "src" || attributeName === "action" ||
attributeName === "formaction" || attributeName === "background" || attributeName === "cite" ||
attributeName === "longdesc" || attributeName === "usemap" || attributeName === "xlink:href"
) {
/* we don't support javascript parsing yet */
// TODO: this filtering rule cannot cover all cases.
if (handlebarsUtils.blacklistProtocol(attributeValue)) {
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ attribute URI Javascript context.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
/* this one is safe to return */
return filters;
}
}
}
filters.push(f);
/* add the attribute value filter */
f = filter.FILTER_NOT_HANDLE;
switch(state) {
case stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_UNQUOTED;
break;
default:
break;
}
filters.push(f);
/* add the correct uri filter */
if (attributeValue.replace(reURIContextStartWhitespaces, '') === "") {
isFullUri = true;
f = filter.FILTER_FULL_URI;
} else {
isFullUri = false;
f = (attributeValue.indexOf('=') === -1) ? filter.FILTER_ENCODE_URI : filter.FILTER_ENCODE_URI_COMPONENT;
}
filters.push(f);
/* add blacklist filters at the end of filtering chain */
if (isFullUri) {
/* blacklist the URI scheme for full uri */
filters.push(filter.FILTER_URI_SCHEME_BLACKLIST);
}
/* add the attribute value filter */
f = filter.FILTER_NOT_HANDLE;
switch(state) {
case stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_UNQUOTED;
break;
default:
break;
}
filters.push(f);
return filters;
// 38, 39, 40 + CSS spec
} else if ((state === stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED) &&
(attributeName === "style")) {
/* we don't support css parser yet
*
* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ attribute style CSS context.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
// 38, 39, 40 + Javascript spec
} else if ((state === stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED) &&
(attributeName.match(/^on/i))) {
/* we don't support js parser yet
*
* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ attrubute on* Javascript context.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
// 38, 39, 40 ONLY and should be placed at last.
} else if (state === stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED ||
state === stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED) {
/* add the attribute value filter */
f = filter.FILTER_NOT_HANDLE;
switch(state) {
case stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_UNQUOTED;
break;
default:
break;
}
filters.push(f);
return filters;
// 42
} else if (state === stateMachine.State.STATE_AFTER_ATTRIBUTE_VALUE_QUOTED) {
/*
* please refer to tests/unit/run-states-spec.js, '{' triggers state change to 12.2.4.34
* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_AFTER_ATTRIBUTE_VALUE_QUOTED state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
// 48
} else if (state === stateMachine.State.STATE_COMMENT) {
filters.push(filter.FILTER_COMMENT);
return filters;
/* add blacklist filters at the end of filtering chain */
if (isFullUri) {
/* blacklist the URI scheme for full uri */
filters.push(filter.FILTER_URI_SCHEME_BLACKLIST);
}
return filters;
} else if (attributeName === "style") { // CSS
/* we don't support css parser yet
* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ attribute style CSS context.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
} else if (attributeName.match(/^on/i)) { // Javascript
/* we don't support js parser yet
* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ attrubute on* Javascript context.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
} else {
/* add the attribute value filter */
f = filter.FILTER_NOT_HANDLE;
switch(state) {
case stateMachine.State.STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
case stateMachine.State.STATE_ATTRIBUTE_VALUE_UNQUOTED:
f = filter.FILTER_ATTRIBUTE_VALUE_UNQUOTED;
break;
default:
break;
}
filters.push(f);
return filters;
}
break;
case stateMachine.State.STATE_AFTER_ATTRIBUTE_VALUE_QUOTED: // 42
/* never fall into state 42 */
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ STATE_AFTER_ATTRIBUTE_VALUE_QUOTED state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
case stateMachine.State.STATE_COMMENT: // 48
filters.push(filter.FILTER_COMMENT);
return filters;
default:
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ NOT HANDLE state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
}
/* we use filter.FILTER_NOT_HANDLE to warn the developers for unsafe output expression,
* and we fall back to default Handlebars escaping filter. IT IS UNSAFE.
*/
filters.push(filter.FILTER_NOT_HANDLE);
msg = "[WARNING] ContextParserHandlebars: Unsafe output expression @ NOT HANDLE state.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, this._strictMode);
return filters;
};

@@ -351,4 +396,6 @@

len = input.length,
str = '', t = 0,
str = '',
obj = {};
obj.str = '';
for(var j=i;j<len;++j) {

@@ -358,14 +405,8 @@ switch (type) {

if (input[j] === '-' && j+3<len && input[j+1] === '-' && input[j+2] === '}' && input[j+3] === '}') {
printChar === true ? this._printChar('--}}') : str += '--}}';
j=j+3;
obj.index = j;
obj.str = str;
printChar === true ? this._printChar('--}}') : obj.str += '--}}';
obj.index = j+3;
return obj;
} else if (input[j] === '-' && j+4<len && input[j+1] === '-' && input[j+2] === '~' && input[j+3] === '}' && input[j+4] === '}') {
printChar === true ? this._printChar('--~}}') : str += '--~}}';
j=j+4;
obj.index = j;
obj.str = str;
printChar === true ? this._printChar('--~}}') : obj.str += '--~}}';
obj.index = j+4;
return obj;

@@ -376,10 +417,8 @@ }

if (input[j] === '}' && j+2<len && input[j+1] === '}' && input[j+2] === '}') {
printChar === true ? this._printChar('}}}') : str += '}}}';
j=j+2;
obj.index = j;
obj.str = str;
printChar === true ? this._printChar('}}}') : obj.str += '}}}';
obj.index = j+2;
return obj;
}
break;
case handlebarsUtils.NOT_HANDLE_EXPRESSION:
case handlebarsUtils.ESCAPE_EXPRESSION:

@@ -393,7 +432,4 @@ case handlebarsUtils.PARTIAL_EXPRESSION:

if (input[j] === '}' && j+1<len && input[j+1] === '}') {
printChar === true ? this._printChar('}}') : str += '}}';
j=j+1;
obj.index = j;
obj.str = str;
printChar === true ? this._printChar('}}') : obj.str += '}}';
obj.index = j+1;
return obj;

@@ -403,3 +439,3 @@ }

}
printChar === true ? this._printChar(input[j]) : str += input[j];
printChar === true ? this._printChar(input[j]) : obj.str += input[j];
}

@@ -412,3 +448,3 @@ msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter close brace of expression.";

// @function module:ContextParserHandlebars._handleEscapeExpression
ContextParserHandlebars.prototype._handleEscapeExpression = function(input, i, len, state) {
ContextParserHandlebars.prototype._handleEscapeExpression = function(input, i, len, nextState) {
var msg, exceptionObj,

@@ -427,3 +463,3 @@ str = '{{',

var stateObj = this.getInternalState();
filters = this._addFilters(state, stateObj, input);
filters = this._addFilters(nextState, stateObj, input);
for(var k=filters.length-1;k>=0;--k) {

@@ -510,3 +546,3 @@ if (re.isSingleID && k === 0) {

// @function module:ContextParserHandlebars._handleBranchExpression
ContextParserHandlebars.prototype._handleBranchExpression = function(input, i, state) {
ContextParserHandlebars.prototype._handleBranchExpression = function(input, i) {
var msg, exceptionObj,

@@ -531,3 +567,3 @@ obj = {};

debug("_handleBranchTemplate: state:"+this.state+",new i:"+ast.index+",lineNo:"+this._lineNo);
debug("_handleBranchTemplate: state:"+result.lastStates[0].state+",new i:"+ast.index+",lineNo:"+this._lineNo);
return obj;

@@ -540,56 +576,2 @@ } catch (err) {

// TODO: context-parser dependent, should move back to context-parser later
// @function ContextParserHandlebars.getInternalState
ContextParserHandlebars.prototype.getInternalState = function() {
var stateObj = {};
stateObj.state = this.state;
stateObj.tagNames = this.tagNames;
stateObj.tagNameIdx = this.tagNameIdx;
stateObj.attributeName = this.attributeName;
stateObj.attributeValue = this.attributeValue;
return stateObj;
};
// TODO: context-parser dependent, should move back to context-parser later
// @function ContextParserHandlebars.setInternalState
ContextParserHandlebars.prototype.setInternalState = function(stateObj) {
// TODO: these 2 apis need to combine.
this.setInitState(stateObj.state);
this.setCurrentState(stateObj.state);
this.tagNames = stateObj.tagNames;
this.tagNameIdx = stateObj.tagNameIdx;
this.attributeName = stateObj.attributeName;
this.attributeValue = stateObj.attributeValue;
};
// TODO: context-parser dependent, should move back to context-parser later
// @function ContextParserHandlebars._deepCompareState
ContextParserHandlebars.prototype._deepCompareState = function(stateObj1, stateObj2) {
var r = true;
[ 'state',
'tagNameIdx',
// attributeName/Value does not affect the state transition
// 'attributeName', 'attributeValue'
].forEach(function(key) {
if (stateObj1[key] !== '' && stateObj2[key] !== '' && stateObj1[key] !== stateObj2[key]) {
r = false;
}
});
[
'tagNames'
].forEach(function(key) {
if (!(stateObj1[key] instanceof Array) || !(stateObj2[key] instanceof Array)) {
r = false;
return;
}
for(var i=0;i<stateObj1.length;++i) {
if (stateObj1[key][i] !== stateObj2[key][i]) {
r = false;
}
}
});
return r;
};
// @function module:ContextParserHandlebars._analyzeContext

@@ -656,3 +638,2 @@ ContextParserHandlebars.prototype._analyzeContext = function(stateObj, obj) {

debugBranch("_analyzeBranchAst:after:program:content");
debugBranch(r.lastStates[0]);

@@ -670,3 +651,2 @@

debugBranch("_analyzeBranchAst:after:program:node");
debugBranch(r.lastStates[0]);

@@ -694,3 +674,2 @@

debugBranch("_analyzeBranchAst:after:inverse:content");
debugBranch(r.lastStates[1]);

@@ -708,3 +687,2 @@

debugBranch("_analyzeBranchAst:before:inverse:node");
debugBranch(r.lastStates[1]);

@@ -729,5 +707,7 @@

if (!this._deepCompareState(r.lastStates[0], r.lastStates[1])) {
msg = "[ERROR] ContextParserHandlebars: Parsing error! Inconsitent HTML5 state after conditional branches. Please fix your template! \n";
msg += "[ERROR] #if.. branch: " + programDebugOutput.slice(0, 50) + "... ("+JSON.stringify(r.lastStates[0])+"\n";
msg += "[ERROR] else branch: " + inverseDebugOutput.slice(0, 50) + "... ("+JSON.stringify(r.lastStates[1])+")";
msg = "[ERROR] ContextParserHandlebars: Parsing error! Inconsitent HTML5 state OR without close tag after conditional branches. Please fix your template! \n";
msg += "[ERROR] #if branch: " + programDebugOutput.slice(0, 50) + "...\n";
msg += "[ERROR] else branch: " + inverseDebugOutput.slice(0, 50) + "...\n";
msg += JSON.stringify(r.lastStates[0]) + "\n";
msg += JSON.stringify(r.lastStates[1]) + "\n";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);

@@ -941,3 +921,3 @@ handlebarsUtils.handleError(exceptionObj, true);

*/
ContextParserHandlebars.prototype._handleTemplate = function(input, i, state) {
ContextParserHandlebars.prototype._handleTemplate = function(input, i, nextState) {

@@ -968,3 +948,3 @@ /* the max length of the input string */

/* _handleRawBlock */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._handleRawBlock(input, i);

@@ -984,6 +964,6 @@ /* advance the index pointer by 1 to the char after the last brace of expression. */

/* _handleRawExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._consumeExpression(input, i, handlebarsExpressionType, true);
/* update the Context Parser's state if it is raw expression. */
this.state = state;
this.state = nextState;
/* advance the index pointer by 1 to the char after the last brace of expression. */

@@ -996,2 +976,12 @@ return obj.index+1;

switch (handlebarsExpressionType) {
case handlebarsUtils.NOT_HANDLE_EXPRESSION:
msg = "[WARNING] ContextParserHandlebars: Not supported expression.";
exceptionObj = new ContextParserHandlebarsException(msg, this._lineNo, this._charNo);
handlebarsUtils.handleError(exceptionObj, false);
/* _consumeExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._consumeExpression(input, i, handlebarsExpressionType, true);
/* advance the index pointer by 1 to the char after the last brace of expression. */
return obj.index+1;
case handlebarsUtils.ESCAPE_EXPRESSION:

@@ -1005,6 +995,6 @@ re = handlebarsUtils.isValidExpression(input, i, handlebarsExpressionType);

/* _handleEscapeExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
obj = this._handleEscapeExpression(input, i, len, state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._handleEscapeExpression(input, i, len, nextState);
/* update the Context Parser's state if it is raw expression. */
this.state = state;
this.state = nextState;
/* advance the index pointer by 1 to the char after the last brace of expression. */

@@ -1021,3 +1011,3 @@ return obj.index+1;

/* _consumeExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._consumeExpression(input, i, handlebarsExpressionType, true);

@@ -1035,3 +1025,3 @@ /* advance the index pointer by 1 to the char after the last brace of expression. */

/* _consumeExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._consumeExpression(input, i, handlebarsExpressionType, true);

@@ -1049,4 +1039,4 @@ /* advance the index pointer by 1 to the char after the last brace of expression. */

/* _handleBranchExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
obj = this._handleBranchExpression(input, i, state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._handleBranchExpression(input, i);
/* advance the index pointer by 1 to the char after the last brace of expression. */

@@ -1064,3 +1054,3 @@ return obj.index+1;

/* _consumeExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._consumeExpression(input, i, handlebarsExpressionType, true);

@@ -1073,3 +1063,3 @@ /* advance the index pointer by 1 to the char after the last brace of expression. */

/* _consumeExpression */
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+state);
debug("_handleTemplate:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i+",state:"+nextState);
obj = this._consumeExpression(input, i, handlebarsExpressionType, true);

@@ -1076,0 +1066,0 @@ /* advance the index pointer by 1 to the char after the last brace of expression. */

@@ -24,2 +24,4 @@ /*

/* type of expression */
HandlebarsUtils.UNHANDLED_EXPRESSION = -1;
HandlebarsUtils.NOT_EXPRESSION = 0;

@@ -74,37 +76,30 @@

var len = input.length,
re;
j;
/* reserved char must be the immediate char right after brace */
if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '>') ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '>')
) {
return HandlebarsUtils.PARTIAL_EXPRESSION;
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '#') ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '#')
) {
return HandlebarsUtils.BRANCH_EXPRESSION;
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '^') ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '^')
) {
// this one is not exact, {{~?^}} will pass!
return HandlebarsUtils.BRANCH_EXPRESSION;
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '/') ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '/')
) {
return HandlebarsUtils.BRANCH_END_EXPRESSION;
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '&') ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '&')
) {
return HandlebarsUtils.REFERENCE_EXPRESSION;
} else if ((input[i] === '{' && i+4<len && input[i+1] === '{' && input[i+2] === '!' && input[i+3] === '-' && input[i+4] === '-') ||
(input[i] === '{' && i+5<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '!' && input[i+4] === '-' && input[i+5] === '-')
) {
return HandlebarsUtils.COMMENT_EXPRESSION_LONG_FORM;
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '!') ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '!')
) {
return HandlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM;
if (input[i] === '{' && i+2<len && input[i+1] === '{') {
j = input[i+2] === '~' ? 3 : 2;
switch(input[i+j]) {
case '>':
return HandlebarsUtils.PARTIAL_EXPRESSION;
case '#':
return HandlebarsUtils.BRANCH_EXPRESSION;
case '^':
// {{~?^}} will pass!, but isValidExpression can guard against
return HandlebarsUtils.BRANCH_EXPRESSION;
case '/':
return HandlebarsUtils.BRANCH_END_EXPRESSION;
case '&':
return HandlebarsUtils.REFERENCE_EXPRESSION;
case '!':
if (i+j+2<len && input[i+j+1] === '-' && input[i+j+2] === '-') {
return HandlebarsUtils.COMMENT_EXPRESSION_LONG_FORM;
}
return HandlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM;
default:
return HandlebarsUtils.ESCAPE_EXPRESSION;
}
}
return HandlebarsUtils.ESCAPE_EXPRESSION;
return HandlebarsUtils.UNHANDLED_EXPRESSION;
};

@@ -187,11 +182,7 @@

var ch = input[i];
if (ch === '~' && input.length > i+1) {
if (ch === '~' && i+1<input.length) {
ch = input[i+1];
}
if (ch === '#' || ch === '/' || ch === '>' || ch === '^' || ch === '!' || ch === '&') {
return true;
} else {
return false;
}
return (ch === '#' || ch === '/' || ch === '>' || ch === '^' || ch === '!' || ch === '&');
};

@@ -198,0 +189,0 @@

@@ -107,5 +107,11 @@ /*

{
title: '/bin/handlebarspc html5 inconsistent state test',
title: '/bin/handlebarspc html5 inconsistent state (42/34) test',
file: './tests/samples/bugs/003.html5.inconsitent.hb',
},
/* remove this test as we don't test for tagNameIdx in deepCompare
{
title: 'state (missing close tag) in branching template test',
file: './tests/samples/bugs/006.state.missing-close-tag.hb',
},
*/
].forEach(function(testObj) {

@@ -124,21 +130,9 @@ it(testObj.title, function(done) {

[
/* remove unnecessary test
{
title: '/bin/handlebarspc html5 inconsistent state test',
file: './tests/samples/bugs/001.hbs',
result: [],
title: './bin/handlebarspc line no and char no reporting test',
file: './tests/samples/bugs/005.line.report.hb',
result: [ /lineNo:2,charNo:38/, /lineNo:4,charNo:91/, /lineNo:8,charNo:177/, /lineNo:10,charNo:274/, /lineNo:12,charNo:298/ ],
},
{
title: '/bin/handlebarspc html5 inconsistent state test',
file: './tests/samples/bugs/001.hbs.original',
result: [],
},
{
title: '/bin/handlebarspc html5 inconsistent state test',
file: './tests/samples/bugs/002.hbs',
result: [],
},
*/
{
title: './bin/handlebarspc html5 inconsistent state test',
title: 'state (tag name) propagation in branching template test',
file: './tests/samples/bugs/004.script.hb',

@@ -148,9 +142,4 @@ result: [],

{
title: './bin/handlebarspc line no and char no reporting test',
file: './tests/samples/bugs/005.line.report.hb',
result: [ /lineNo:2,charNo:38/, /lineNo:4,charNo:91/, /lineNo:8,charNo:177/, /lineNo:10,charNo:274/, /lineNo:12,charNo:298/ ],
},
{
title: 'state (attribute name) propagation in logical template test',
file: './tests/samples/bugs/006.state.hb',
title: 'state (attribute name) propagation in branching template test',
file: './tests/samples/bugs/006.state.attribute-name.hb',
result: [ /{{{y styleoutput}}}/, /{{{yavd classoutput}}}/ ],

@@ -157,0 +146,0 @@ },

@@ -19,100 +19,106 @@ /*

/*
* this test is to simulate the case that the developer is putting the output place holder after
* the state 12.2.4.34 and test what correct filter should be applied.
*
* the next state of state 12.2.4.34 is 12.2.4.1 (>,EOF), 12.2.4.35 (a-zA-Z,null,",',<,=,anything) and 12.2.4.43 (/),
* as 'anything' triggers the state change to 12.2.4.35, so we need to handle this state accordingly
*
* this test is to simulate the case of transitting to the before-attribute-name-state (12.2.4.34) from
* attribute-value-(quoted)-state (12.2.4.40), after-attribute-value-(quoted)-state (12.2.4.42) and
* self-closing start tag state (12.2.4.43), as output place holder cannot be put at the state 34,
* we don't need to handle it (exception).
*/
it('HTML5 Context Parser placeholder after before-attribute-name-state (12.2.4.34) test', function(){
var p1 = new Parser();
var html = '<div id="1" {';
p1.contextualize(html);
var states = p1.getStates();
expect(states.toString()).to.equal('1,8,10,10,10,34,35,35,37,38,38,42,34,35');
it('HTML5 Context Parser placeholder TO before-attribute-name-state (12.2.4.34) test', function(){
[
{ html: '<option value=123 {', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,40,40,40,34,35'},
{ html: '<option value="123" {', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,38,38,42,34,35'},
{ html: '<option value="123"/ {', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,38,38,42,34,34,35'},
{ html: '<option value="123"/', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,38,38,42,43'},
].forEach(function(testObj) {
var p1 = new Parser();
p1.contextualize(testObj.html);
var states = p1.getStates();
expect(states.toString()).to.equal(testObj.states);
});
});
/*
* this test is to simulate the case that the developer is putting the output place holder after
* the state 12.2.4.36 and test what correct filter should be applied.
*
* the next state of state 12.2.4.36 is 12.2.4.1 (>,EOF), 12.2.4.35 (a-zA-Z,null,",',<,anything), 12.2.4.37 (=) and 12.2.4.43 (/),
* as 'anything' triggers the state change to 12.2.4.35, so we need to handle this state accordingly
*
* this test is to simulate the case of transitting to the attribute-name-state (12.2.4.35) from
* before-attribute-name-state (12.2.4.34) and after-attribute-name-state (12.2.4.36),
* so we need to handle the state 35.
*/
it('HTML5 Context Parser placeholder after after-attribute-name-state (12.2.4.36) test', function(){
var p1 = new Parser();
var html = '<option value="1" selected {';
p1.contextualize(html);
var states = p1.getStates();
expect(states.toString()).to.equal('1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,42,34,35,35,35,35,35,35,35,35,36,35');
it('HTML5 Context Parser placeholder TO attribute-name-state (12.2.4.35) test', function(){
[
{ html: '<div id="1" {', states: '1,8,10,10,10,34,35,35,37,38,38,42,34,35'},
{ html: '<option value="1" selected {', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,42,34,35,35,35,35,35,35,35,35,36,35'},
].forEach(function(testObj) {
var p1 = new Parser();
p1.contextualize(testObj.html);
var states = p1.getStates();
expect(states.toString()).to.equal(testObj.states);
});
});
/*
* this test is to simulate the case that the developer is putting the output place holder after
* the state 12.2.4.37 and test what correct filter should be applied.
*
* the next state of state 12.2.4.37 is 12.2.4.1 (>,EOF), 12.2.4.38 ("), 12.2.4.39 ('), and 12.2.4.40 (&,null,<,=,`,anything),
* as 'anything' triggers the state change to 12.2.4.40, so we need to handle this state accordingly
*
* this test is to simulate the case of transitting to the after-attribute-name-state (12.2.4.36) from
* attribute-name-state (12.2.4.35), as output place holder cannot be put at the state 36,
* we don't need to handle it (exception).
*/
it('HTML5 Context Parser placeholder after before-attribute-value-state (12.2.4.37) test', function(){
var p1 = new Parser();
var html = '<option value={';
p1.contextualize(html);
var states = p1.getStates();
expect(states.toString()).to.equal('1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,40');
it('HTML5 Context Parser placeholder TO after-attribute-name-state (12.2.4.36) test', function(){
[
{ html: '<option value="1" selected ', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,42,34,35,35,35,35,35,35,35,35,36'},
].forEach(function(testObj) {
var p1 = new Parser();
p1.contextualize(testObj.html);
var states = p1.getStates();
expect(states.toString()).to.equal(testObj.states);
});
});
/*
* this test is to simulate the case that the developer is putting the output place holder after
* the state 12.2.4.38 and test what correct filter should be applied.
*
* the next state of state 12.2.4.38 is 12.2.4.1 (EOF) and 12.2.4.42 ("),
* as 'anything' does not trigger the state change, so we need to handle this state accordingly
*
* this test is to simulate the case of transitting to the before-attribute-value-state (12.2.4.37) from
* attribute-name-state (12.2.4.35) and after-attribute-name-value-state (12.2.4.36),
* as output place holder cannot be put at the state 37, we don't need to handle it.
*/
it('HTML5 Context Parser placeholder after attribute-value-(double-quoted)-state (12.2.4.38) test', function(){
var p1 = new Parser();
var html = '<option value="{';
p1.contextualize(html);
var states = p1.getStates();
expect(states.toString()).to.equal('1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38');
it('HTML5 Context Parser placeholder TO before-attribute-value-state (12.2.4.37) test', function(){
[
{ html: '<option value=', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37'},
{ html: '<option value =', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,36,37'},
].forEach(function(testObj) {
var p1 = new Parser();
p1.contextualize(testObj.html);
var states = p1.getStates();
expect(states.toString()).to.equal(testObj.states);
});
});
/*
* this test is to simulate the case that the developer is putting the output place holder after
* the state 12.2.4.39 and test what correct filter should be applied.
*
* the next state of state 12.2.4.39 is 12.2.4.1 (EOF) and 12.2.4.42 ('),
* as 'anything' does not trigger the state change, so we need to handle this state accordingly
*
* this test is to simulate the case of transitting to the attribute-value-(double-quoted)-state (12.2.4.38),
* attribute-value-(single-quoted)-state (12.2.4.39), attribute-value-(unquoted)-state (12.2.4.40)
* so we need to handle the state 38,39 and 40.
*/
it('HTML5 Context Parser placeholder after attribute-value-(single-quoted)-state (12.2.4.39) test', function(){
var p1 = new Parser();
var html = '<option value=\'{';
p1.contextualize(html);
var states = p1.getStates();
expect(states.toString()).to.equal('1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,39,39');
it('HTML5 Context Parser placeholder TO attribute-value-(double/single/un-quoted)-state (12.2.4.38/39/40) test', function(){
[
{ html: '<option value="{', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38'},
{ html: "<option value='{", states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,39,39'},
{ html: '<option value={', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,40'}
].forEach(function(testObj) {
var p1 = new Parser();
p1.contextualize(testObj.html);
var states = p1.getStates();
expect(states.toString()).to.equal(testObj.states);
});
});
/*
* this test is to simulate the case that the developer is putting the output place holder after
* the state 12.2.4.42 and test what correct filter should be applied.
*
* the next state of state 12.2.4.42 is 12.2.4.1 (>,EOF), 12.2.4.34 (space etc,anything), 12.2.4.43 (/),
* however, 'anything' triggers the state change to 12.2.4.34 and reconsume logic,
* it replaces the states buffer with 12.2.4.34, this falls back to the previous handling case above.
*
* this test is to simulate the case of transitting to the after-attribute-value-(quoted)-state (12.2.4.42) from
* attribute-value-(single-quoted)-state (12.2.4.39), attribute-value-(unquoted)-state (12.2.4.40),
* as output place holder cannot be put at the state 42, we don't need to handle it (exception).
*/
it('HTML5 Context Parser after-attribute-value-(quoted)-state (12.2.4.42) test', function(){
var p1 = new Parser();
var html = '<div id="1"{';
p1.contextualize(html);
var states = p1.getStates();
expect(states.toString()).to.equal('1,8,10,10,10,34,35,35,37,38,38,34,35');
it('HTML5 Context Parser placeholder TO after-attribute-value-(quoted)-state (12.2.4.42) test', function(){
[
{ html: '<option value="{}"', states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,38,38,38,42'},
{ html: "<option value='{}'", states: '1,8,10,10,10,10,10,10,34,35,35,35,35,35,37,39,39,39,42'},
].forEach(function(testObj) {
var p1 = new Parser();
p1.contextualize(testObj.html);
var states = p1.getStates();
expect(states.toString()).to.equal(testObj.states);
});
});
});
}());

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc